Re: Default value for readonly properties
| From: | Valentin Udaltsov | Date: | Fri, 07 Jun 2024 12:46:00 +0000 |
| Subject: | Re: Default value for readonly properties | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-123536@lists.php.net to get a copy of this message | ||
On Friday, 7 June 2024 at 12:11, Claude Pache <claude.pache@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