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

Reply via email to