On Friday, 7 June 2024 at 12:11, Claude Pache <claude.pa...@gmail.com> wrote:
> Hi, > > As of today, readonly properties cannot have a default value: > > ```php > class UltimateQuestion { > readonly int $answer = 42; // Fatal error: Readonly property > Question::$answer cannot have default value > } > ``` > > The rationale given in the original RFC ( > https://wiki.php.net/rfc/readonly_properties_v2) was: > > As the default value counts as an initializing assignment, a readonly > property with a default value is essentially the same as a constant, and > thus not particularly useful. The notion could become more useful in the > future, if new expressions are allowed as property default values. At the > same time, depending on how exactly property initialization would work in > that case, having a default value on a readonly property could preclude > userland serialization libraries from working, as they would not be able to > replace the default-constructed object. Whether or not this is a concern > depends on whether the property is initialized at time of object creation, > or as an implicit part of the constructor (or similar). As these are open > questions, the conservative choice is to forbid default values until these > questions are resolved. > > A new fact is that properties will be able to be declared in interface > since PHP 8.4 (as introduced in the recently accepted property hooks RFC). > It is true that, for an individual class, a readonly property is > functionally equivalent to a constant. But my class implements an interface > (or, before 8.4, follows a non-written protocol), and whether that > particular implementation choose to always hold the same value for a > specific property is irrelevant. > > > ```php > interface Question { > public int $answer { get; } > } > class UltimateQuestion implements Question { > readonly int $answer = 42; > } > ``` > > Therefore I think it is reasonable for readonly properties to accept > default values. > > About the concern given in the original RFC: “having a default value on a > readonly property could preclude userland serialization libraries from > working, as they would not be able to replace the default-constructed > object”... TBH, as I almost never serialise my objects, and even less often > customise serialisation, I can only guess what the effective issue is. My > best guess is that a custom `__unserialize()` method would not be able to > reinstate the incriminated readonly properties, because those would already > have been initialised with the default value. If this is the case, a > solution is to do for `__uninitialize()` the same thing that we have done > for `__clone()`, see: > https://wiki.php.net/rfc/readonly_amendments#proposal_2readonly_properties_can_be_reinitialized_during_cloning > > —Claude > Hi, Claude! Thank you for bringing up this issue! I agree that the phrase "a readonly property with a default value is essentially the same as a constant" is not correct for all cases. For example, I might have a class like this: ```php final readonly class ObjectCollector { private SplObjectStorage $storage; public function __construct() { $this->storage = new SplObjectStorage(); } public function add(object $object): void { $this->storage->attach($object); } } (new ObjectCollector())->add(new stdClass()); ``` It's a fully working example (https://3v4l.org/dSpQO) where `$storage` can not be replaced with a constant. And it would be nice if `$storage` could be initialized without a constructor. I just looked at some of my PHP >=8.1 projects and noticed that I have a few places where the constructor has no parameters and only exists to initialize readonly properties with smth like `SplQueue`. -- Valentin Udaltsov