Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130092 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 C9EBF1A00BC for ; Wed, 18 Feb 2026 21:29:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1771450199; bh=2wDYoVNxAR6zqk11tmsoxgZzw9SANaHAzu/HaK6mU5w=; h=Date:Subject:To:References:From:In-Reply-To:From; b=dg+i4I3zwFe7zro1IWQtnqRuIS4KrJcAun7DQRqXPy5SO4cMrypdgzHOF5wa/My/e aSVZzooaf/4oOrvGR5Ey1atQJ8eOSlWvEff6z/jdE4L+L4ppr6bJ97D0luh3X/x9II 5RScSwK3vo5o4DpgCiro2diiDD0GJqiz32qoPvXVlaR0A1je/30tl2yfUtJLSfk7Lk Ls5l+MzEHfc+Kv8wswvkcsEDE6YC5dRgiFmDAUH+i/iwPjdd7PnsMA52V4zAyPb4hp Jg+GnIwM/lEow+LFL6tZbv9SNSXE6ejcXa6NPtB5VeJFhIlBHbcf9ZghrKOeyFMtbg n4EvrH0Vwr/sg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 147B918005A for ; Wed, 18 Feb 2026 21:29:58 +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 ; Wed, 18 Feb 2026 21:29:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1771450180; bh=zMmQbgNvZ6QSHLU0JcejbXy3M4FTsLNZbJv3YzYwQJQ=; h=Message-ID:Date:MIME-Version:Subject:To:References:From: In-Reply-To:Content-Type:from:to:cc:subject:message-id; b=AbtMe+WD7ZeO9cCJuTM8HQN0lfX1yqYVgQp6yFlIn9/LDgVMznPTUe6fLPwsfl3/m cs/U2erTDJbe4YXJKX4R5CpCmRKO4rHt4bjpk15GoisUIPYUBlx/4/CLIG4+dt+GHI qdMzr/gFSI+Zj6r/Dbbf2Qin+1JQM1ev2ZeMHbBRmhzA7YP+kfs1A+Udl5WomQVVH+ AKV44m/hPLIHpg/qEfdgBNGIGAdVdjjVSnV3zAiD0wuk1WqTVvLc+hlRzQc2bp26mz iBU6gmodfECfC9N8R/Mdn5JRgLT9worWwgxL7CZj5LKBMwOMOB7tPm5nBmXbdEmgYl lTa33GdUdLo/g== Message-ID: <3cd0d869-5a5b-467c-8eb4-3f8647ba7aa7@bastelstu.be> Date: Wed, 18 Feb 2026 22:29:39 +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 , 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/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