<? phpukraine СПІВБЕСІДИ
Пошук по платформі
CORE PHP · MIDDLE ЧАСТО ПИТАЮТЬ

Що таке property hooks у PHP 8.4+?

Це можливість оголосити get і set логіку прямо на властивості, без окремих методів і без магії __get/__set.

Чим property hooks кращі за геттери й сеттери?
Що нового в PHP 8.4 для класів?
Чи можна оголосити hook в інтерфейсі?
PHP 8.4 property hooks інваріанти

Property hooks дозволяють оголосити логіку читання й запису прямо на властивості. Замість пари getName()/setName() клас має public string $name { get => ...; set => ...; }, а зовнішній код працює зі звичайним доступом до поля. Обійти сеттер неможливо: будь-яке присвоєння, зокрема в промоутнутому конструкторі, проходить через хук, тому інваріант виконується завжди.

На відміну від __get/__set хуки статично типізовані й привʼязані до конкретної властивості. IDE підказує тип, PHPStan перевіряє тіло хука, а рантайм не платить за виклик магічного методу на кожне звернення. Якщо хук get не читає саму властивість, вона стає віртуальною й не займає памʼяті, як обчислюване fullName.

Інтерфейси теж отримали цю можливість: public string $label { get; } у контракті замінює метод getLabel(). Клас може реалізувати вимогу і хуком, і звичайною публічною властивістю.

Практична порада: не переписувати всі геттери на хуки заради стилю. Найбільшу користь дають місця, де інваріант уже порушувався через прямий запис, і value objects, де валідація має жити поруч із даними.

final class Product
{
    public function __construct(
        public string $name {
            set(string $value) {
                if (trim($value) === '') {
                    throw new InvalidArgumentException('Name cannot be empty.');
                }
                $this->name = trim($value);
            }
        },
        public int $priceCents { set => max(0, $value); },
    ) {}

    // Віртуальна властивість: памʼять не виділяється, значення обчислюється
    public string $label { get => $this->name.' — '.number_format($this->priceCents / 100, 2).' грн'; }
}

interface HasLabel
{
    public string $label { get; }   // інтерфейс вимагає властивість, а не метод getLabel()
}

$p = new Product('  Кава ', 1990);
$p->name = '';      // InvalidArgumentException: сеттер неможливо обійти
echo $p->label;     // Кава — 19.90 грн
Що hook оголошується на самій властивості, тому обійти set неможливо: інваріант виконується завжди, навіть при прямому присвоєнні.
Що на відміну від __get/__set це статично типізовано: IDE й PHPStan бачать тип, а аналізатор перевіряє тіло хука.
Що властивість із хуком get без backing value стає віртуальною й не займає памʼяті.
Що інтерфейси можуть вимагати властивість з get або set, і це замінює пари getX/setX у контрактах.
Тверезу оцінку: масова міграція геттерів на hooks заради стилю не окупається, переписують те, де вже болять інваріанти.
Плутати з readonly: readonly забороняє зміну після ініціалізації, hooks додають логіку на читання й запис.
Вважати hooks заміною __get і __set: магічні методи працюють для неоголошених властивостей, hooks лише для оголошених.
Не знати, що властивість з хуками не можна зробити readonly, а всередині set треба писати $this->prop = ..., щоб зберегти значення.
Змішувати з asymmetric visibility public private(set), яка теж зʼявилась у 8.4, але вирішує іншу задачу.
ПОРАДА

Згадайте, що масова міграція геттерів на hooks заради стилю не окупається — переписують те, де вже болять інваріанти. І назвіть другу фічу 8.4 поруч: asymmetric visibility.

оновлено 3 вересня 2026 · ліцензія CC-BY-SA-4.0 Знайшли неточність? Напишіть →
ПЕРЕВІРТЕ СЕБЕ

Hooks оголошуються на самій властивості, і сеттер не можна обійти, тому інваріант виконується завжди.