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

Reply via email to