Re: [RFC] Allow Reassignment of Promoted Readonly Properties in Constructor

From: Date: Wed, 18 Feb 2026 21:29:39 +0000
Subject: Re: [RFC] Allow Reassignment of Promoted Readonly Properties in Constructor
References: 1 2 3 4 5 6 7 8 9  Groups: php.internals 
Request: Send a blank email to internals+get-130092@lists.php.net to get a copy of this message
Hi On 2/16/26 19:20, Nicolas Grekas wrote:
To be sure I understood you well: you are suggesting that mutability should be scoped to the constructor that declares the property (not any constructor on the object).
Yes, because otherwise you might rely on implementation details of the parent constructor: Depending on whether the parent constructor reassigns internally, your reassignment in the child constructor either succeeds or fails.
This makes sense and I’ve implemented exactly that model: - Reassignment is allowed only while the declaring class constructor is active (including methods/closures called from it). - A child constructor can no longer reassign a parent-declared promoted readonly property. - “Child sets first, then parent::__construct()” now throws as expected. - The thrown Error is catchable from the child (around parent::__construct()), but not from inside the parent body before implicit CPP init. - Calling __construct() on an already-constructed object still cannot mutate readonly state. I also updated the RFC text and examples to state this explicitly, and added/updated tests for the inheritance/preemption scenarios.
Thank you. I've checked the RFC and the explanation and semantics make sense to me. I've also reviewed (parts) of the tests and provided some feedback there. I'll take another look at the tests when you made the adjustments to make sure that everything in the RFC is properly tested to make sure we didn't miss and edge case.
Anything else?
Yes, there is one edge case related to inheritance that isn't mentioned in the RFC and from what I see it's not tested either. Child classes can redefine readonly properties and they are then “owned” by the child class. Thus we need to explain what happens in that case. I've prepared example for the three relevant cases I can think of. The follow from the existing semantics in a straight-forward fashion, but it's good to spell them out explicitly (and particularly test them). 1. Parent uses CPP, child redefines and reassigns.
    class P1 {
        public function __construct(
            public readonly string $x = 'P',
        ) { }
    }
    class C1 extends P1 {
        public readonly string $x;
        public function __construct() {
            parent::__construct();
            $this->x = 'C'; // This should fail.
        }
    }
2. Parent uses CPP and reassigns, child redefines.
    class P2 {
        public function __construct(
            public readonly string $x = 'P1',
        ) {
            $this->x = 'P2'; // This should be legal.
        }
    }
    class C2 extends P2 {
        public readonly string $x;
        public function __construct() {
            parent::__construct();
        }
    }
3. Parent uses CPP, child uses CPP redefinition.
    class P3 {
        public function __construct(
            public readonly string $x = 'P',
        ) { }
    }
    class C3 extends P3 {
        public function __construct(
            public readonly string $x = 'C1',
        ) {
            parent::__construct(); // This should fail.
        }
    }
Best regards Tim Düsterhus

« previous php.internals (#130092) next »