Le mar. 3 févr. 2026 à 10:30, Rob Landers <[email protected]> a écrit :
> > > On Tue, Feb 3, 2026, at 10:22, Nicolas Grekas wrote: > > > > Le mar. 3 févr. 2026 à 10:00, Rob Landers <[email protected]> a écrit : > > > On Tue, Feb 3, 2026, at 09:56, Nicolas Grekas wrote: > > Hi Rob, > > Le mar. 3 févr. 2026 à 09:50, Rob Landers <[email protected]> a écrit : > > > On Mon, Feb 2, 2026, at 22:14, Nicolas Grekas wrote: > > Hi Marco, > > Le lun. 2 févr. 2026 à 11:54, Marco Pivetta <[email protected]> a écrit : > > Hey Nicolas, > > > On Thu, 22 Jan 2026 at 16:34, Nicolas Grekas <[email protected]> > wrote: > > Dear all, > > Here is a new RFC for you to consider: > https://wiki.php.net/rfc/promoted_readonly_constructor_reassign > > > > What happens if one calls `$obj->__construct(1, 2, 3)` (on an already > instantiated `$obj`) in the context of this patch? > > > Thanks for asking, I didn't think about this. This made me also think > about ReflectionClass::newInstanceWithoutConstructor(). > I clarified this in the RFC, see "Direct __construct() Calls Cannot Bypass > Readonly" and "Reflection: Objects Created Without Constructor". > Patch and PR updated also if anyone wants to run some code where this RFC > can be played with. > > Cheers, > Nicolas > > > Hi Nicolas, > > Under "Child Classes Can Reassign Parent Properties": this feels like a > major footgun. Calling parent::__construct() won't allow a reset (per the > rules of calling a constructor directly); which would completely break > inheritance... but then in the examples it says that calling a constructor > directly can reset it -- but you can't? > > This feels really inconsistent to me. > > — Rob > > > Yes, the text was ambiguous. The implementation allows > parent::__construct() during the initial construction (normal inheritance), > and only blocks explicit __construct() calls after construction completed. > I’ve clarified this in the RFC. > > Nicolas > > > Will this result in a catchable error? I assume so, so a valid pattern > during inheritance might be to put these in a try/catch so children can set > them first? > > FWIW, in my Records RFC, properties were fully mutable during construction > for exactly this reason. > > > > The existing behavior is preserved: if a reassignment fails, it throws a > catchable Error. The implicit CPP assignment in a parent constructor > happens before the parent body, so a child cannot "set first" and then call > ''parent::__construct()'' to avoid it; a try/catch in the parent cannot > intercept it. But a try/catch in the child can catch of course. > > Does that answer your question? > > > So, this could end up with partial application of state? Or does it > rollback? For example: > > class Box { > public function __construct(readonly int $x, readonly int $y, readonly > bool $isSquare = false) { > $this->isSquare = $x == $y; > } > } > > class Square extends Box { > public function __construct(readonly int $size) { > $this->isSquare = true; > try { > parent::__construct($size, $size); // what is the state after it > throws? > } catch(\Throwable) {} > } > } > > (I spent over a year thinking about this stuff ... so if you're interested > in more edge cases, I can dig up my notes) > You're correct. Although such code explicitly decided to opt-in for ignoring anything from the parent, and that's always a very bad idea. > FWIW, in my Records RFC, properties were fully mutable during construction for exactly this reason. I wouldn't mind making readonly properties mutable during initial construction if we can get a consensus on this. I've not been brave enough to consider this was possible. I might be wrong :D
