PHP 8.2: Readonly-классы / классы только для чтения
На практике, добавление в PHP 8.2 readonly-класса, это означает, что все свойства этого класса — readonly-свойства, доступны только для чтения. Это полезно при использовании DTO или VO, когда класс содержит только публичные readonly-свойства.
Другими словами, вместо того, чтобы писать так:
class BlogData
{
public function __construct(
public readonly string $title,
public readonly Status $status,
public readonly ?DateTimeImmutable $publishedAt = null,
) {}
}
Теперь вы можете писать так:
readonly class BlogData
{
public function __construct(
public string $title,
public Status $status,
public ?DateTimeImmutable $publishedAt = null,
) {}
}
Я уже писал о readonly-свойствах, поэтому давайте для начала быстро всё просуммируем:
- readonly-свойства могут быть записаны только один раз — обычно в конструкторе;
- только типизированные свойства могут быть объявлены
readonly
; - они не могут иметь значение по умолчанию (если вы не используете определяемые в конструкторе свойства);
- флаг
readonly
не может быть изменён при наследовании; - вы не можете удалить readonly-свойство.
Поскольку readonly-классы — просто синтаксический сахар для того, что бы сделать все свойства класса доступными только для чтения, это означает, что те же правила применяются и к readonly-классам.
Задаётся один раз
Все свойства readonly-класса могут быть заданы только один раз и не могут быть удалены:
readonly class BlogData { /* … */ }
$blogData = new BlogData(/* … */);
$blogData->title = 'other'; // Not works
unset($blogData->title); // Not works
Только типизированные свойства
Readonly-класс может иметь только типизированные свойства:
readonly class BlogData
{
public string $title;
public $mixed; // Not works
}
Без статических свойств
Поскольку readonly-свойства не могут быть static
, readonly-класс не может иметь статических свойств:
readonly class BlogData
{
public static string $title; // Not works
}
Без значений по умолчанию
Свойства readonly-класса не могут иметь значение по умолчанию, если вы не используете свойства определяемые в конструкторе:
readonly class BlogData
{
public string $title = 'default'; // Not works
}
readonly class BlogData
{
public function __construct(
public string $title = 'default', // This works
) {}
}
Никаких изменений при наследовании
Вы не можете изменить readonly
флаг класса во время наследования:
readonly class BlogData { /* … */ }
class NewsItemData extends BlogData { /* … */ } // Not works
Без динамических свойств
Readonly-классы не допускают использования динамических свойств. Это не окажет большого влияния, поскольку динамические свойства устарели в PHP 8.2, но это означает, что вы не можете добавить атрибут #[AllowDynamicProperties]
для readonly-класса
#[AllowDynamicProperties] // Not works
readonly class BlogData { /* … */ }
Reflection
Наконец, есть новый метод ReflectionClass
для определения является ли класс readonly
: ReflectionClass::isReadOnly()
. Вы также можете использовать ReflectionClass::getModifiers()
, который будет включать флаг ReflectionClass::IS_READONLY
.