Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127976 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 304BD1A00BC for ; Wed, 9 Jul 2025 16:22:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752078054; bh=md3m4KDHhJah6xftPVqNHQh6KSs9hGuUtrfW/gLbUTo=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=Lt0fSb4igMzAeWU12nYQpW7n0u17M/s7PC4J1wW6PS35uBV11C8SRHPt3XeTnpCt5 0Q23sqNvsGMgMuHjGGtJIOMxjKxXD2UFT1uy/Iq6Jd3bAaiwcMTKyFXJaUy3gydmOs R4/arxdJ9jbriiJUZfao8Hiz0/CJBb2Bw/N1y1eVYRTqpNtls3/oPySXqp3YBxekBn bER3Mg71j/3dkh1qZaWdbXtUeUjiv9T+98evuE9WuVgqnTbyiHJogwml3HyVH9jx9O 3UyHTQkwvfHfh4DmKRmmJVXrZ2ztrOpUADUVdf5AnGv+4hbHQdLBvbWPzRz6qPlxDc pRLuxhb+vYeGQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CBB8518006E for ; Wed, 9 Jul 2025 16:20:53 +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=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from fout-a3-smtp.messagingengine.com (fout-a3-smtp.messagingengine.com [103.168.172.146]) (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, 9 Jul 2025 16:20:53 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfout.phl.internal (Postfix) with ESMTP id 6971FEC0492; Wed, 9 Jul 2025 12:22:43 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Wed, 09 Jul 2025 12:22:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:cc:content-type:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm3; t=1752078163; x= 1752164563; bh=md3m4KDHhJah6xftPVqNHQh6KSs9hGuUtrfW/gLbUTo=; b=B YoEnUXl0F1eL2MAMdq5yFZFPpLyMn9cMqkps318qj/FnxBPIYdKFSp8Qm68xwUam yETnd23zCNtPnJ8f0qdxqDsWgKFs+EXwlo+jwMTHxX6WRbH8iq2ogyL1LLsywlAb dEMcyCwwCzarhbPK5+AZ5sZhlz7VGmYKw0csM4c8nMC4IB8F/YujZwKWavvcMILm K92qeDQYpHv3u+H+SWDVi942Ik+dsTZhSbdYHxXZ5uoPrTB1x3kzrcQ5DMBuo/oE vMKxnYjMY9NYJPWaxiKcweSDZYJNXJ+chkXOiDCY36s74gn59qZAornkdks4uCrR U6+P5zqHBIeKLgB8Bkgpw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1752078163; x=1752164563; bh=md3m4KDHhJah6xftPVqNHQh6KSs9hGuUtrf W/gLbUTo=; b=aAxU0bfGdntQzNwcFhBmEJhIr0tSuQd+WrNn5k/YJC7ZrSA4ONu wVf3lWUzSqJoJHqGBkHYYqayCpt7XgRdEBsVxWxquFxDSKIg4/whkUfZW5Pm0+yC 0IvaZzWt8zimBA1oaYkJ9J3wKtPbEqsZLAPAj8qKgbS8tMSeYM3NgJdwconeMzrY Br5FgAwGeAshfqn7zjKP31NsvSS7ab1S0UEtC0njTu3YOoZorxfQifGc/xSodPQ9 bYrcFVpdiWjCV4SAHTVXEepFhcnGm/tpyoaJeEg6QtUwwwxMT4Jd3eSKs+yYkVWW i4RVhnAg0EenAcPGNd5C/BISlSCw9bNPGtw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdefkedtfecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogfuuh hsphgvtghtffhomhgrihhnucdlgeelmdenucfjughrpefoggffhffvvefkjghfufgtsegr tderreertdejnecuhfhrohhmpedftfhosgcunfgrnhguvghrshdfuceorhhosgessghoth htlhgvugdrtghouggvsheqnecuggftrfgrthhtvghrnhepjefhffegleeiudejfedvveef tedtheffjeegfeffvedtvdeivdeuteekfeetkedunecuffhomhgrihhnpeefvheglhdroh hrghdpphhhphdrnhgvthenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgr ihhlfhhrohhmpehrohgssegsohhtthhlvggurdgtohguvghspdhnsggprhgtphhtthhope egpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehlrghrrhihsehgrghrfhhivghl ughtvggthhdrtghomhdprhgtphhtthhopegtlhgruhguvgdrphgrtghhvgesghhmrghilh drtghomhdprhgtphhtthhopehnihgtohhlrghsrdhgrhgvkhgrshdophhhphesghhmrghi lhdrtghomhdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvg ht X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 2571D182007A; Wed, 9 Jul 2025 12:22:42 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: T5f4527d1a0d4de24 Date: Wed, 09 Jul 2025 18:22:21 +0200 To: "Nicolas Grekas" , "Claude Pache" Cc: "Larry Garfield" , "php internals" Message-ID: <26eccbae-0ecb-467e-a8a8-06df297fbd01@app.fastmail.com> In-Reply-To: References: <1e8634d7-ac1a-4025-b4e2-1948aabf5251@app.fastmail.com> <46857A6D-5EAF-44AF-A2DE-9B40AF8DE8C8@gmail.com> Subject: Re: [PHP-DEV] [RFC] Readonly property hooks Content-Type: multipart/alternative; boundary=40fef28314e6462fa71a86129d29812c From: rob@bottled.codes ("Rob Landers") --40fef28314e6462fa71a86129d29812c Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Wed, Jul 9, 2025, at 13:39, Nicolas Grekas wrote: > Thanks for your detailed thoughts, Claude. I'd like to offer my perspe= ctive on some of the points you raised. >=20 > Le mer. 9 juil. 2025 =C3=A0 12:53, Claude Pache a =C3=A9crit : >>=20 >>=20 >>> Le 8 juil. 2025 =C3=A0 17:32, Nicolas Grekas > a =C3=A9crit : >>>=20 >>> I read Claude's concern, and I agree with Larry's response: the engi= ne already allows readonly to be bypassed using __get. The added hook do= esn't make anything more lenient. >>>=20 >>=20 >> It is true that readonly could be bypassed by __get(); but this is a = legacy behaviour, and you have to take an explicit step to make it possi= ble. For those unaware of the awful hack, here is a minimal test case: >>=20 >> https://3v4l.org/N78An >>=20 >> where the `unset(...)` is mandatory to make it =E2=80=9Cwork=E2=80=9D. >>=20 >> Are we obligated to sanction shortcomings of legacy concepts in newly= introduced concepts that are supposed to replace them? Or can we do som= ething better? I=E2=80=99ve outlined in a previous email what I think is= a better design for such situation (namely an `init` hook). >>=20 >> Also, the fact that __get() is not yet deprecated means that we can s= till use the aforementioned hack until/unless we=E2=80=99ve implemented = a proper solution. In the worst case, you can still use a non-readonly h= ooked property and document the intended invariants in phpdoc. >=20 >=20 > __get is certainly not legacy; removing it would break many use cases = without proper alternatives. > The behavior after unset() has been promoted to a language feature whe= n readonly properties were introduced *because* it helps solve real worl= d use cases. > I've been asked recently by Gina if those use cases were covered by eg= native lazy proxies. The answer is *no*, because native lazy proxies co= ver only part of the lazy-proxying domain: what remains is proxying by i= nterface and proxying internal classes, and those require a way to proxy= all property accesses, which is why magic methods are required. >=20 > With the argument that __get can be used to implement the non-readonly= -ness, we could also say that hooks are not needed, because they can be = implemented using __get. Yet, language aesthetics are important, and we = welcomed hooks for this reason. Being able to easily lazy-init thanks to= hooks on readonly would be a welcome improvement to me. >=20 > That being said, about your init proposal, I think that could work. I'= d just do it a bit differently: instead of introducing a new "init" hook= , I'd prefer having "set" mean "init" for readonly properties. But I kno= w nothing about the engine on the topic so I can't comment on the feasib= ility aspect. I'll leave this to others. >=20 > Just a word about using hooks vs __get for lazy-init: the really hard = part when using __get is emulating the public/protected/private visibili= ty rules. Hooks make this a non-issue. Yet hooks - unfortunately - can't= be used as a generic lazy-init implementation because of their behavior= related to references. That's another topic, but still related, to rein= force that __get is certainly not legacy. > =20 >=20 >>=20 >>=20 >>=20 >>> If a class is final and uses readonly with either hooks or __get, th= en that's the original author's choice. There's no need for extra engine= -assisted strictness in this case. You cannot write such code in a non-r= eadonly way by mistake, so it has to be by intent. >>>=20 >>=20 >> Enforcing as strictly as possible its intended invariants is a good d= esign for a robust language. Yes, it implies that users cannot (or can h= ardly) escape annoying constraints. For example, you can=E2=80=99t exten= d a final class, even if you think that you have good reason for it, lik= e constructing a mock object. >=20 >=20 > That's not strictness when the root concept is already filled with con= ceptual holes... I'm surprised nobody ever proposed the concept of an *i= mmutable* keyword, that'd be like readonly but that'd accept only also-i= mmutable values. Until this happens, using readonly for that is a fallac= y I'm sorry... To me that invalidates all related arguments. >=20 > Nicolas https://wiki.php.net/rfc/records I=E2=80=99ll probably return back to it after 8.5 is released. Knowing w= hat I know today, there are a lot of things id remove.=20 =E2=80=94 Rob --40fef28314e6462fa71a86129d29812c Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Wed, Jul 9, 2025, at 13:39, Nicolas Grekas wrote:
Thanks for your detailed thoughts, Claude. I'd like to offe= r my perspective on some of the points you raised.

<= div class=3D"qt-gmail_quote qt-gmail_quote_container">
Le mer. 9 juil. 2025 =C3=A0 12:53, Clau= de Pache <claude.pache@gmai= l.com> a =C3=A9crit :

Le 8 juil. 2025 =C3=A0 17:32, Nico= las Grekas <nicolas.grekas+php@gmail.com> a =C3=A9crit :
<= br>
I read Claude's concern, and I agree with Larry's response: the en= gine already allows readonly to be bypassed using __get. The added hook = doesn't make anything more lenient.


It is true that readonly could be bypassed = by __get(); but this is a legacy behaviour, and you have to take an expl= icit step to make it possible. For those unaware of the awful hack, here= is a minimal test case:


=
where the `unset(...)` is mandatory to make it =E2=80=9Cwork=E2= =80=9D.

Are we obligated to sanction shortcomin= gs of legacy concepts in newly introduced concepts that are supposed to = replace them? Or can we do something better? I=E2=80=99ve outlined in a = previous email what I think is a better design for such situation (namel= y an `init` hook).

Also, the fact that __get() = is not yet deprecated means that we can still use the aforementioned hac= k until/unless we=E2=80=99ve implemented a proper solution. In the worst= case, you can still use a non-readonly hooked property and document the= intended invariants in phpdoc.

<= div>
__get is certainly not legacy; removing it would brea= k many use cases without proper alternatives.
The behavior aft= er unset() has been promoted to a language feature when readonly propert= ies were introduced *because* it helps solve real world use cases.
=
I've been asked recently by Gina if those use cases were covered by= eg native lazy proxies. The answer is *no*, because native lazy proxies= cover only part of the lazy-proxying domain: what remains is proxying b= y interface and proxying internal classes, and those require a way to pr= oxy all property accesses, which is why magic methods are required.

With the argument that __get can be used to impleme= nt the non-readonly-ness, we could also say that hooks are not needed, b= ecause they can be implemented using __get. Yet, language aesthetic= s are important, and we welcomed hooks for this reason. Being able to ea= sily lazy-init thanks to hooks on readonly would be a welcome improvemen= t to me.

That being said, about your init propo= sal, I think that could work. I'd just do it a bit differently: instead = of introducing a new "init" hook, I'd prefer having "set" mean "ini= t" for readonly properties. But I know nothing about the engine on the t= opic so I can't comment on the feasibility aspect. I'll leave this to ot= hers.

Just a word about using hooks vs __get fo= r lazy-init: the really hard part when using __get is emulating the publ= ic/protected/private visibility rules. Hooks make this a non-issue. Yet = hooks - unfortunately - can't be used as a generic lazy-init implem= entation because of their behavior related to references. That's an= other topic, but still related, to reinforce that __get is certainly not= legacy.
 


<= br>

I= f a class is final and uses readonly with either hooks or __get, then th= at's the original author's choice. There's no need for extra engine-assi= sted strictness in this case. You cannot write such code in a non-readon= ly way by mistake, so it has to be by intent.

=

Enforcing as strictly as possible its i= ntended invariants is a good design for a robust language. Yes, it impli= es that users cannot (or can hardly) escape annoying constraints. For ex= ample, you can=E2=80=99t extend a final class, even if you think that yo= u have good reason for it, like constructing a mock object.
<= /blockquote>


That's not strictness whe= n the root concept is already filled with conceptual holes... I'm s= urprised nobody ever proposed the concept of an *immutable* keyword= , that'd be like readonly but that'd accept only also-immutable values. = Until this happens, using readonly for that is a fallacy I'm sorry.= .. To me that invalidates all related arguments.

Nicolas

https://wiki.php.net/rfc/records

I=E2=80=99ll probably return back to it after 8.5= is released. Knowing what I know today, there are a lot of things id re= move. 

=E2=80=94 Rob --40fef28314e6462fa71a86129d29812c--