====== PHP RFC: Readonly classes ====== * Date: 2021-08-04 * Author: Máté Kocsis * Status: Accepted * Target Version: PHP 8.2 * Implementation: https://github.com/php/php-src/pull/7305 ===== Introduction ===== PHP 8.1 added support for readonly properties via [[rfc:readonly_properties_v2|PHP RFC: Readonly properties 2.0]]. However, it's still not easy to declare (quasi-)immutable classes, especially if they contain many properties. Therefore, this RFC proposes to add support for ''readonly'' classes. ===== Proposal ===== The usage of the ''readonly'' modifier added by [[rfc:readonly_properties_v2|PHP RFC: Readonly properties 2.0]] is extended to classes: readonly class Test { public string $prop; } Doing so will implicitly mark all instance properties of a class as readonly. Furthermore, it will prevent the creation of dynamic properties. readonly class Foo { public int $bar; public function __construct() { $this->bar = 1; } } $foo = new Foo(); $foo->bar = 2; // Fatal Error: Uncaught Error: Cannot modify readonly property Foo::$bar $foo->baz = 1; // Fatal Error: Uncaught Error: Cannot create dynamic property Foo::$baz [[rfc:deprecate_dynamic_properties|PHP RFC: Deprecate dynamic properties]] added support for the ''#[AllowDynamicProperties]'' attribute which makes it possible to create dynamic properties without triggering errors. In order not to violate the read-only constraint, marking readonly classes with the above attribute is a compile-time error: #[AllowDynamicProperties] readonly class Foo { } // Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo ==== Restrictions ==== As neither untyped, nor static properties are covered by the [[rfc:readonly_properties_v2#restrictions|Readonly properties RFC]], readonly classes cannot declare them either: readonly class Foo { public $bar; } // Fatal error: Readonly property Foo::$bar must have type readonly class Foo { public static int $bar; } // Fatal error: Readonly class Foo cannot declare static properties ==== Inheritance ==== Similarly how overriding of readonly properties works, a readonly class can only extend a readonly parent: readonly class A {} readonly class B extends A {} // valid But both of the following are illegal: readonly class A {} class B extends A {} // Fatal error: Non-readonly class B cannot extend readonly class A class A {} readonly class B extends A {} // Fatal error: Readonly class B cannot extend non-readonly class A ==== Reflection ==== A ''ReflectionClass::isReadOnly()'' method is added, which reports whether a class is declared as read-only. Additionally, ''ReflectionClass::getModifiers()'' will also include the ''ReflectionClass::IS_READONLY'' flag. ===== Backward Incompatible Changes ===== None. ===== Errata ===== * [[https://github.com/php/php-src/issues/9285|https://github.com/php/php-src/issues/9285]]: It used to be possible to add non-readonly properties to readonly classes via traits. As on PHP 8.2 RC 1, traits cannot be used by readonly classes if they define any non-readonly property, otherwise a compilation error is emitted. ===== Vote ===== Voted started on 2022-04-27, ending on 2022-05-11 * Yes * No