Re: [RFC] Readonly property hooks
| From: | Rob Landers | Date: | Wed, 09 Jul 2025 16:22:21 +0000 |
| Subject: | Re: [RFC] Readonly property hooks | ||
| References: | 1 2 3 4 5 6 7 8 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-127976@lists.php.net to get a copy of this message | ||
On Wed, Jul 9, 2025, at 13:39, Nicolas Grekas wrote:
> Thanks for your detailed thoughts, Claude. I'd like to offer my perspective on some of the
> points you raised.
>
> Le mer. 9 juil. 2025 à 12:53, Claude Pache <claude.pache@gmail.com> a écrit :
>>
>>
>>> Le 8 juil. 2025 à 17:32, Nicolas Grekas <nicolas.grekas+php@gmail.com
>>> <mailto:nicolas.grekas%2Bphp@gmail.com>> a écrit :
>>>
>>> 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.
>>>
>>
>> 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 possible. For those unaware of the awful hack, here is
>> a minimal test case:
>>
>> https://3v4l.org/N78An
>>
>> where the
unset(...) is mandatory to make it “work”.
>>
>> Are we obligated to sanction shortcomings of legacy concepts in newly introduced concepts
>> that are supposed to replace them? Or can we do something better? I’ve outlined in a previous
>> email what I think is a better design for such situation (namely an
>> init hook).
>>
>> Also, the fact that __get() is not yet deprecated means that we can still use the
>> aforementioned hack until/unless we’ve implemented a proper solution. In the worst case, you can
>> still use a non-readonly hooked property and document the intended invariants in phpdoc.
>
>
> __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 when readonly properties
> 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 by interface and proxying internal classes, and those require a way
> to proxy all property accesses, which is why magic methods are required.
>
> 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.
>
> 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 know nothing about the engine
> on the topic so I can't comment on the feasibility aspect. I'll leave this to others.
>
> Just a word about using hooks vs __get for lazy-init: the really hard part when using __get is
> emulating the public/protected/private visibility 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 reinforce that __get is
> certainly not legacy.
>
>
>>
>>
>>
>>> 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.
>>>
>>
>> Enforcing as strictly as possible its intended invariants is a good design for a robust
>> language. Yes, it implies that users cannot (or can hardly) escape annoying constraints. For
>> example, you can’t extend a final class, even if you think that you have good reason for it, like
>> constructing a mock object.
>
>
> That's not strictness when the root concept is already filled with conceptual holes...
> I'm surprised 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’ll probably return back to it after 8.5 is released. Knowing what I know today, there are a lot
of things id remove.
— Rob