В PHP 8.1 появилась поддержка свойств классов «только для чтения» (read-only). Свойство класса, объявленное как read-only, может быть инициализировано только один раз, и последующие изменения этого свойства не допускаются.
Свойства класса только для чтения объявляются с помощью ключевого слова readonly * в типизированном свойстве.
class User {
public readonly int $uid;
public function __construct(int $uid) {
$this->uid = $uid;
}
}
$user = new User(42); Значения свойств только для чтения могут быть заданы только из самого класса — либо из конструктора, либо из другого метода. После установки значения дальнейшие изменения этого свойства не допускаются, даже внутри класса.
class User {
public readonly int $uid;
public function __construct(int $uid) {
$this->uid = $uid;
}
} $user = new User(42);
$user->uid = 56; Error: Cannot modify readonly property User::$uid in ...:... readonly в качестве имени функции
Начиная с PHP 8.1 и более поздних версий, readonly является зарезервированным ключевым словом PHP. Тем не менее, оно явно разрешает объявлять функции с именем readonly для совместимости с существующими PHP-приложениями, которые объявляют собственные функции readonly , такими как WordPress.
Свойства readonly в конструкторе
Продвижение свойств в конструкторе (Constructor property promotion), появившееся в PHP 8.0, также поддерживает новый флаг readonly в конструкторе.
class User {
public function __construct(public readonly int $uid) {}
} Объявление выше эквивалентно следующему:
class User {
public readonly int $uid;
public function __construct(int $uid) {
$this->uid = $uid;
}
} Инициализация свойств
Свойство, объявленное как readonly , может быть инициализировано из любого места внутри класса. Логичнее всего инициализировать свойства только для чтения из конструктора, но делать это именно там не обязательно.
class User {
public readonly int $uid;
public function fetch(int $uid) {
$this->uid = $uid;
}
}
$user = new User();
$user->fetch(42); Приведенный выше фрагмент кода корректен, поскольку свойство readonly $uid записывается только один раз, из метода fetch() . Однако второй вызов функции fetch() приведет к выбросу Error, так как он предполагает перезапись свойства $uid .
$user = new User(); $user->fetch(42); $user->fetch(16); Error: Cannot modify readonly property User::$uid in ...:...
Инициализация свойства readonly вне области видимости класса не допускается:
class User {
public readonly int $uid;
}
$user = new User();
$user->uid = 9; Error: Cannot initialize readonly property User::$uid from global scope in ...:... Контроль ограничения «только для чтения»
PHP активно препятствует изменению свойства readonly . Это включает в себя прямую установку значения, инкремент, ссылки и операции с массивами.
class User {
public readonly int $uid;
public function __construct(int $uid) {
$this->uid = $uid;
}
}
$user = new User(42); Ни одно из изменений в следующем неисчерпывающем списке не допускается:
$user->uid = 16; $user->uid++; $uid_ref =& $user->uid;
Удаление свойства readonly через unset
Кроме того, удаление уже инициализированного свойства readonly с помощью unset также не допускается:
unset($user->uid); Error: Cannot unset readonly property User::$uid in ...:...
Ограничения
Свойства readonly могут значительно сократить шаблонный код, который часто используется для ограничения доступа на запись к свойствам класса, что теперь можно упростить с помощью свойства public readonly . Однако флаг readonly может не подойти для некоторых сценариев использования.
Поддерживается только для типизированных свойств
Свойства только для чтения поддерживаются только для типизированных свойств. Это связано с тем, что свойства, объявленные без указания типа, неявно имеют значение null до тех пор, пока не будет задано значение, что несовместимо с ограничением read-only. Типизированные свойства остаются «неинициализированными» до тех пор, пока им не будет присвоено значение.
Попытка объявить свойство readonly без указания типа приведет к ошибке:
class User {
public readonly $uid;
} Fatal error: Readonly property User::$uid must have type in ... on line ... Мутабельность
Свойство readonly не обеспечивает неизменяемость (immutability) объектов. Например, если свойство readonly содержит объект, сам этот объект может изменяться:
class User {
public string $username;
}
class Post {
public readonly User $author;
public function __construct(User $author) {
$this->author = $author;
}
}
$user = new User();
$user->username = 'Foo';
$post = new Post($user);
$user->username = 'Bar'; В приведенном выше фрагменте класс Post хранит свойство readonly author . Сам объект $user может изменяться, и свойство readonly не предотвращает модификацию самого объекта.
Если требуется неизменяемость, обязательно клонируйте ( clone ) объект перед присваиванием:
class Post {
public readonly User $author;
public function __construct(User $author) {
- $this->author = $author;
+ $this->author = clone $author;
}
} Влияние на обратную совместимость
readonly является зарезервированным ключевым словом в PHP 8.1. Использование имени readonly (без учета регистра) для любых существующих классов или других символов приведет к синтаксической ошибке в PHP 8.1.
Перенести функциональность readonly в более старые версии PHP невозможно. Тем не менее, аннотации @readonly / @property-read распознаются инструментами статического анализа, такими как Psalm.
class User {
/** @readonly */
public string $username;
}
Комментарии (0)
Пока нет комментариев — будьте первым.