Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130022 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 0F9391A00BC for ; Thu, 5 Feb 2026 19:29:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1770319763; bh=y/vSaJuc4V/gkdQgH/tYBvNldEZnnf9Pf3NK2akZWiA=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=YQpdn26IJbphFVGJX2ImVYqEJI15ChyRKZ0YElkStq4Z9/W2hzpJf5IX3FP2KJ3QW Ip1YJ05D2KXfprxCQ1IY2dxggw4hiRZXspoaJMhUaJKNqTzKTY4m0GM8v26NyO+jLL Dq29BaXqbHXF7WqpYsu3Qyhw3vZbxiQ23S9CV0Jg7LCuXInsiSHd6S+wI/znAf9ARK IdGhNrWrutFu1p87EnQssJiT6VxiF24ev4QMW1UXmDURBTLu/vKFVp3fdVi9xaccpg 0tyi12YiAGjGzZMKWCJZAT+dCCUxdQtNRy/PT+2FQzbeLHUlKi4NYOEIxeOUbGSVsU cI52qblyO/Tcw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 6899C1801D6 for ; Thu, 5 Feb 2026 19:29:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from chrono.xqk7.com (chrono.xqk7.com [176.9.45.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 5 Feb 2026 19:29:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1770319755; bh=8k+MDyQo8jy4mgCX+iBmceGyoUFd3Ov9NqKeUhJh/1E=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type:from:to:cc:subject:message-id; b=c/HN8OLIyvjiHWom6Hq39+6KwGo05adiuf81Eh4xVhCBI4GP1tfVFx/qJHIqJsUnm ZCDfFJetfLIh5cX/krKsqw3MAEtuCMGLM8lTd9LEAgi55hsOUuGlKgkSogZhnDtOr/ smbupG4/oq7OHqvOVUlb0AjJJkWx15nOUpmPEPQZWoZu5ogWUgpBrIPie90B9QoPhz CJivhHFlWnTWjBFhuPcjWA/UL1V0q41eXesrudmTJkJw1Mb2iu5qE+3R/VqKIYqZ8W Qn6/lT8U7N0GJKY5YR4ZCtl6XZZWJ+jMpd0fdLaahRCLDGTp+XHPWMgJUQdC9jXAfg 7WvCaNmZ2eIaA== Message-ID: Date: Thu, 5 Feb 2026 20:29:12 +0100 Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Subject: Re: [PHP-DEV] [RFC] Allow Reassignment of Promoted Readonly Properties in Constructor To: Nicolas Grekas , Rob Landers Cc: PHP Internals List References: <4b74f9a1-96d2-4104-abdd-fe56c5e7016c@app.fastmail.com> <585bfc82-a522-43ec-be42-b8945952fe8b@app.fastmail.com> Content-Language: en-US In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=C3=BCsterhus?=) Hi On 2/3/26 10:22, Nicolas Grekas wrote: > 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 This is a good example that as far as I can tell is not explicitly spelled out in the RFC: Please include an example where the *child* sets a readonly property defined in the parent before calling the parent constructor. class P { public function __construct( public readonly string $x = 'P', ) { } } class C extends P { public function __construct() { $this->x = 'C'; parent::__construct(); // Will this throw or not? } } More generally, as Rob, I stumbled upon the “Child Classes Can Reassign Parent Properties” section, because it's least obviously correct behavior to me. My understanding of this RFC is that it is intended to solve the case where the class itself needs to perform some “post-processing” on a promoted readonly property that it owns. Specifically, the property becomes locked once the constructor completes. For the example in “Child Classes Can Reassign Parent Properties” my mental model says that `$prop` is owned by `Parent_`, since `Parent_` is the class that declared it. Thus it would be natural for me to ”lock” `$prop` once the `parent::__construct()` call completes. If the child class needs to do special processing on the property, it has two options: 1. Not call the parent constructor. If the parent constructor logic is unfit, then not calling the constructor is the right thing rather than trying to revert part of what it did to a readonly property. 2. Call `parent::__construct()` with an appropriately modified value: parent::__construct('child override'); So to describe my expected semantics in more technical terms: The implementation should “unlock” the property after the “auto-generated promotion logic” finished and should “relock” the property when the method with the auto-generated promotion logic finishes. In other words: public function __construct( public readonly string $prop = 'parent default', ) { // Parent does NOT reassign here } should be equivalent to: public function __construct( string $prop = 'parent default', ) { $this->prop = $prop; // unlock $this->prop (set IS_PROP_REINITABLE) try { // Parent does NOT reassign here } finally { // lock $this->prop (unset IS_PROP_REINITABLE) } } With this logic, the answer to initial “will this throw” question of this email would be “yes”, because the implicit `$this->prop = $prop` assignment happens before the unlock. I believe it would also more closely match the semantics of `__clone()`. Best regards Tim Düsterhus