Hi everyone, Le jeu. 19 févr. 2026 à 10:49, Nicolas Grekas <[email protected]> a écrit :
> Hi Tim, > > Le mer. 18 févr. 2026 à 22:29, Tim Düsterhus <[email protected]> a écrit : > >> 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. >> } >> } >> >> > > Thanks, I've added new test cases to cover this. > I've also improved tests as suggested on the PR. > And finally I updated the implementation to reuse IS_PROP_REINITABLE > instead of adding new flags + use an approach that doesn't require walking > the call stack. > PR and RFC updated accordingly, all green. > One last update following more review comments by Tim: the reassign window is now scoped to the CPP-owning constructor. See updated wording at https://wiki.php.net/rfc/promoted_readonly_constructor_reassign Cheers, Nicolas
