PHP RFC: Readonly classes
- Date: 2021-08-04
- Author: Máté Kocsis kocsismate@php.net
- 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 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 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
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 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: 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