Вопрос проверяет знание сокращённого синтаксиса объявления свойств класса через конструктор в PHP 8, а также понимание его плюсов и ограничений.
Promotion-свойства в PHP 8 позволяют объявлять и инициализировать свойства класса прямо в списке аргументов конструктора, без дублирования кода. Вместо того чтобы отдельно объявлять свойства и присваивать им значения в теле конструктора, достаточно указать модификатор видимости в параметре. Это уменьшает "шум" в коде и делает класс компактнее и нагляднее. Однако так можно объявлять только нестатические свойства, и такой синтаксис иногда хуже подходит для сложной логики инициализации. Также он не работает с параметрами без модификаторов видимости или с теми, где нужно сложное присваивание.
Promotion-свойства (constructor property promotion) — это синтаксический сахар, упрощающий объявление и инициализацию свойств в классах.
Определение: Constructor property promotion — это возможность объявить и проинициализировать свойство класса прямо в сигнатуре конструктора через указание модификатора видимости у параметра.
До PHP 8 типичный класс с несколькими полями выглядел так:
php
class User {
private string $name;
private string $email;
private int $age;
public function __construct(string $name, string $email, int $age)
{
$this->name = $name;
$this->email = $email;
$this->age = $age;
}
}
Здесь возникает дублирование:
переменные объявляются как свойства
те же имена повторяются в параметрах конструктора
затем ещё раз повторяются при присваивании this->... = ...
В PHP 8 можно записать тот же класс более компактно:
php
class User {
public function __construct(
private string $name,
private string $email,
private int $age,
) {}
}
Что происходит "под капотом":
Для каждого параметра с модификатором видимости (public, protected, private) автоматически создаётся свойство класса.
Это свойство получает:
указанный модификатор видимости
указанный тип
имя, совпадающее с именем параметра
В конструкторе автоматически выполняется присваивание этого параметра в свойство.
Фактически PHP сам за вас генерирует обычные объявления свойств и присваивания.
Важно понимать, что promotion-свойства не "волшебство", а более короткий синтаксис с рядом ограничений:
Только в конструкторе
Promotion работает только в методе __construct. Нельзя использовать этот синтаксис в других методах.
Обязателен модификатор видимости
Если в параметре нет public/protected/private, это обычный аргумент, а не свойство:
php
class User {
public function __construct(
private string $name,
string $rawPassword // это просто аргумент, не свойство
) {}
}
Нельзя использовать для статических свойств
Статические свойства не поддерживаются для promotion.public static в списке параметров конструктора использовать нельзя.
Нельзя смешивать с var и другими нестандартными модификаторами
Promotion работает только с public, protected, private, при необходимости с readonly (в новых версиях).
Нельзя использовать сложные выражения в объявлении
Вы можете задать значение по умолчанию, но не сложную логику. Сложная логика должна быть в теле конструктора.
Когда стоит применять promotion:
Меньше шаблонного кода (boilerplate)
Не нужно объявлять свойства отдельно.
Не нужно прописывать this->... = ... для каждого параметра.
Лучшая читабельность при простых моделях
Вся структура объекта видна в одном месте — в сигнатуре конструктора. Это удобно для DTO, value-объектов и простых доменных сущностей.
Меньше риска ошибок при копировании
Меньше повторений — меньше шансов забыть инициализировать какое-то свойство.
Хорошо комбинируется с readonly
Для неизменяемых объектов (например, value object) синтаксис становится очень выразительным:
php
class Point {
public function __construct(
public readonly float $x,
public readonly float $y,
) {}
}
Есть ситуации, в которых promotion-свойства усложняют понимание или становятся неудобными:
Сложная инициализация
Если при создании объекта вам нужно выполнять валидацию, преобразование или дополнительную логику, лучше явно описать свойства и тело конструктора:
php
class User {
private string $email;
public function __construct(string $email)
{
// валидация e-mail
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($email);
}
}
Формально можно использовать promotion и отдельные свойства/логику, но код станет менее прозрачным.
Модели с множеством необязательных полей
При большом количестве параметров конструктор с promotion может стать длинным и тяжело читаемым. Иногда проще использовать обычные свойства и сеттеры/билдер.
Переопределение конструктора в наследовании
В сложной иерархии классов, где конструкторы активно переопределяются, использование promotion в базовых и наследниках иногда запутывает читающего код.
Promotion-свойства — это удобный синтаксический сахар для простых, "плоских" объектов с прямой инициализацией полей. Их стоит активно использовать для DTO, value-объектов и простых сущностей, но быть аккуратным в местах со сложной логикой конструирования и наследованием.