Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127959 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 1FBF11A00BC for ; Tue, 8 Jul 2025 15:33:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1751988678; bh=tyNzRhcBlF1B9mizzkmafEAWKiAoH1/8MW5zoN20Ubk=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=UhzMk5a2GVA/DhLN7guafXbUdQZQ6hmnSSG7MfRhjCb7sHHCv1+Bk5hrhqps/fzO9 7aMVfPTNY+zua48mjj5snh7KMy8Xoc6h9WwjA3+KgHuH6Fk4D75z76xQUrTFBkoaOG VFK+JHLfUdiv9KCtr0Q9pe2/9PmPpv0cMe7sfT0h47oyq2t4cj84EHi3xlGmmd5Tiz UVV+u9/R5z5/uH/3Qz3zIt/cA0W8N81A+8U9VOcBNxGh7QZmr4YYbRqfKMTC7bya6/ M2bMLsfAjKYeUHmB1uZSL0/fTa9p/1s/sTvq9SyGU60nAbS0cZ7OvmIAIPLkwZEh05 wNMtCrVXONY2A== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 813721804F4 for ; Tue, 8 Jul 2025 15:31:17 +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=-3.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, 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 mail-lj1-f176.google.com (mail-lj1-f176.google.com [209.85.208.176]) (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 ; Tue, 8 Jul 2025 15:31:07 +0000 (UTC) Received: by mail-lj1-f176.google.com with SMTP id 38308e7fff4ca-32b3b250621so41403251fa.2 for ; Tue, 08 Jul 2025 08:32:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1751988776; x=1752593576; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=UIBpuBeJ4MPgegNDWYJ7JsNfkT/joEYs15nBZnjA9SQ=; b=ENyMh9Eirjyg21eVSrGSG7aoZgcGkB7oMLzKRgBS936v/WwR0MG96yEArP/DDBu4ib tFgvnLTiTzG+mCg2/9INxOuingdXeKWbuU18cu6B6L3bjIQU1E2O3HUgF2cZE0N8MdqS h6XZWeiHmRmQI8z9KS4zUJFeYXrhkQWLq8XZb6r8fRyYB6RBxLN00zBQCmyR9aQ6N/lc V1jf7pOa9o+LrG9GeqwcSoJyX0Tz82pdXMI/4jBGj7T3KvomWCQEULo1GACvKowXn9M/ sIfCfYoCT3ms5Z9zXk6QLmPTk5rTOuF9nN2q1l1v6sQp/G3RVsCYANuCOO6EWeqWuuXY QOdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751988776; x=1752593576; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=UIBpuBeJ4MPgegNDWYJ7JsNfkT/joEYs15nBZnjA9SQ=; b=NJ8v/nS4dFPtM1OtO9PPIv8Lm7HDnobniJwnankrsSznxbTRAd1762baYKGNLNKxdk XVi4G79T0g5lTdodHCNxwq6p5HA/R5yo18N7qblyiIViOJ9qRy7+S5aJDUpKi1A0EH21 02IRFst/51VLOMXiqzHO0a0KLkkQF4Jh9E/IYXZHj+THE8AGR/DpDApzxGrJmF7hWSix uJH2U69ICc2Cn2bM6+Jzo5rQddjWhb8N6bH7fDisFFtVepljj2WF9K3+omijjE4J6Xvh k7gMuKCZNIAgo7gU+QMeLuYyDCDVVFAFQfGlgj1ByuslGcLrbFWtSCkj2Cyq6js/hHuv kMGg== X-Gm-Message-State: AOJu0Yx2HO6SwhDVbBrLMk4x2LSKwh0Zw0PvYH5GyR1v3BlByTd6cQuE +K6CDywy9gc7/tsdnKt3vDwKcXpdhAp6DOSaDTTVLCU72AonB4OfXqnIWn0v+mKHv+whXty4W9n OPinsYv1vjOt2rWvNUK2rz38azvuEJW/Lm0fEAEg= X-Gm-Gg: ASbGncsEFtMs/BVOiUD/2wiq29EunhrNLCXDWi4RKB2HHcH0SoP3OhYI5Qr8XBhgfFk 7s1B0NO0z3/KVO+2cjJbd7kEX4013VrpA4ovXVYeWbcC7iQmzXCdGQSK7wtGMVBCo20WASdxXLM oURJjbc+sGYRvlE7IKPntDLm+2OtLzySbdCzzFb8EL8A== X-Google-Smtp-Source: AGHT+IG6Ce0/HZne0ef86hF56snKE2d6M57xIRUVMiMbtYoxS7uiNfnXrzBH/DpcvBg1/utqHqQ5GQG6kYf/VOs64dU= X-Received: by 2002:a2e:b5b3:0:b0:32b:533a:f4d6 with SMTP id 38308e7fff4ca-32f39b49133mr9566641fa.34.1751988775743; Tue, 08 Jul 2025 08:32:55 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1e8634d7-ac1a-4025-b4e2-1948aabf5251@app.fastmail.com> In-Reply-To: Date: Tue, 8 Jul 2025 17:32:44 +0200 X-Gm-Features: Ac12FXwKwLZHNZWi3nowIFZ49zx_QvpYs__ZAukBRvh7QbmeacVmy974E5oULYA Message-ID: Subject: Re: [PHP-DEV] [RFC] Readonly property hooks To: Larry Garfield Cc: php internals Content-Type: multipart/alternative; boundary="000000000000a0f7a506396cac01" From: nicolas.grekas+php@gmail.com (Nicolas Grekas) --000000000000a0f7a506396cac01 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Larry et al. Le mar. 8 juil. 2025 =C3=A0 17:12, Larry Garfield = a =C3=A9crit : > On Tue, Jul 1, 2025, at 9:27 AM, Tim D=C3=BCsterhus wrote: > > Hi > > > > Am 2025-06-09 17:11, schrieb Larry Garfield: > >> I also fleshed out the __get mention with an example that shows what > >> you can already do today, and in fact could since 8.1 when readonly wa= s > >> introduced. The hard guarantee of idempotency has never actually been > >> there. (This also speaks to Claude's concern.) > > > > I don't think this really resolves Claude's concern. While it is > > certainly true that the guarantees do not currently hold, I don't > > believe this is strong enough of a reason not to provide for stronger > > guarantees in a *newly introduced feature*. The point of property hooks > > is for me that =E2=80=9Cdynamic properties=E2=80=9D are easier to reaso= n about compared > > to `__get()`. As a user when accessing a proper `readonly` property, I > > do not want to check if there is a property hook that might result in > > non-readonly behavior. As an engine developer I want to be able to > > optimize based on the `readonly`-ness of a property. Without such > > guarantees, the =E2=80=9Creadonly=E2=80=9D keyword does not provide val= ue to me. > > The only way to make the readonliness fully guaranteed would be to force = a > readonly property to be cached; (IE, the hook is only called at all if t= he > property is uninitialized.) But there's no obvious way to make that clea= r > in the code that it's what's happening. > > > I also believe the LazyProduct example to be broken, since lazy-loading > > individual properties might result in an object that is internally > > consistent if the database changes in-between. > > That's true with any lazy-loading scenario. The use of hooks doesn't > change that at all. > This RFC makes sense to me. I read Claude's concern, and I agree with Larry's response: the engine already allows readonly to be bypassed using __get. The added hook doesn't make anything more lenient. I also read Tim's argument that new features could be stricter. If one wants to be stricter and forbid extra behaviors that could be added by either the proposed hooks or __get, then the answer is : make the class final. This is the only real way to enforce readonly-ness in PHP. If a class is final and uses readonly with either hooks or __get, then 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-readonly way by mistake, so it has to be by intent. Nicolas PS: as I keep repeating, readonly doesn't immutable at all. I know this is written as such in the original RFC, but the concrete definition and implementation of readonly isn't: you can set mutable objects to readonly properties, and that means even readonly classes/properties are mutable, in the generic case. --000000000000a0f7a506396cac01 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi=C2=A0Larry et al.

Le=C2=A0mar. 8 juil. 2025 =C3=A0=C2=A017:12, Larry Garfield <larry@garfieldtech.com> a =C3=A9c= rit=C2=A0:
On Tu= e, Jul 1, 2025, at 9:27 AM, Tim D=C3=BCsterhus wrote:
> Hi
>
> Am 2025-06-09 17:11, schrieb Larry Garfield:
>> I also fleshed out the __get mention with an example that shows wh= at
>> you can already do today, and in fact could since 8.1 when readonl= y was
>> introduced.=C2=A0 The hard guarantee of idempotency has never actu= ally been
>> there.=C2=A0 (This also speaks to Claude's concern.)
>
> I don't think this really resolves Claude's concern. While it = is
> certainly true that the guarantees do not currently hold, I don't =
> believe this is strong enough of a reason not to provide for stronger =
> guarantees in a *newly introduced feature*. The point of property hook= s
> is for me that =E2=80=9Cdynamic properties=E2=80=9D are easier to reas= on about compared
> to `__get()`. As a user when accessing a proper `readonly` property, I=
> do not want to check if there is a property hook that might result in =
> non-readonly behavior. As an engine developer I want to be able to > optimize based on the `readonly`-ness of a property. Without such
> guarantees, the =E2=80=9Creadonly=E2=80=9D keyword does not provide va= lue to me.

The only way to make the readonliness fully guaranteed would be to force a = readonly property to be cached;=C2=A0 (IE, the hook is only called at all i= f the property is uninitialized.)=C2=A0 But there's no obvious way to m= ake that clear in the code that it's what's happening.

> I also believe the LazyProduct example to be broken, since lazy-loadin= g
> individual properties might result in an object that is internally > consistent if the database changes in-between.

That's true with any lazy-loading scenario.=C2=A0 The use of hooks does= n't change that at all.


<= div>This RFC makes sense to me.

I read Claude'= s concern, and I agree with Larry's response: the engine already allows= readonly to be bypassed using __get. The added hook doesn't make anyth= ing more lenient.

I also read Tim's argument t= hat new features could be stricter. If one wants to be stricter and forbid = extra behaviors that could be added by either the proposed hooks or __get, = then the answer is : make the class final. This is the only real way to enf= orce readonly-ness in PHP.

If a class is final and= uses readonly with=C2=A0either hooks or __get, then that's the origina= l author's choice. There's no need for extra engine-assisted strict= ness in this case. You cannot write such code in a non-readonly way by mist= ake, so it has to be by intent.

Nicolas
= PS: as I keep repeating, readonly doesn't immutable at all. I know this= is written as such in the original RFC, but the concrete definition and im= plementation of readonly isn't: you can set mutable objects to readonly= properties, and that means even readonly classes/properties are mutable, i= n the generic case.
--000000000000a0f7a506396cac01--