> Le 23 nov. 2023 à 08:56, Rowan Tommins <rowan.coll...@gmail.com> a écrit :
> 
> On 23 November 2023 01:37:06 GMT, Claude Pache <claude.pa...@gmail.com> wrote:
>> What you describe in the last sentence is what was initially designed and 
>> implemented by the RFC: https://wiki.php.net/rfc/typed_properties_v2 
>> (section Overloaded Properties).
>> 
>> However, it was later changed to the current semantics (unset() needed in 
>> order to trigger __get()) in https://github.com/php/php-src/pull/4974
> 
> 
> Good find. So not only is it not specified this way in the RFC, it actually 
> made it into a live release, then someone complained and we rushed out a more 
> complicated version "to avoid WTF". That's really unfortunate.
> 
> I'm not at all convinced by the argument in the linked bug report - whether 
> you get an error or an unexpected call to __get, the solution is to assign a 
> valid value to the property. And making the behaviour different after unset() 
> just hides the user's problem, which is that they didn't expect to *ever* 
> have a call to __get for that property.
> 
> But I guess I'm 4 years too late to make that case.
> 

Hi, 

I think that the legitimacy of the current behaviour is not something to be 
convinced by abstract reasoning like we are doing now (otherwise, it wouldn’t 
probably have waited a live release to be implemented in a rush), but something 
that can be understood only by considering the conflicting uses of  __get(), 
which leads to conflicting expectations, and how they managed to live together 
despite a fundamental contradiction:

1. __get() is used to implement virtual properties (as mentioned in the linked 
bug report). For this use case, access to a declared property should not call 
__get() (whose implementation may be hidden away in a superclass).

2. __get() is used to implement lazy properties. For this use case, access to 
an uninitialised (or unset, or undeclared) property should call __get().

The two expectations did live together as long as declared properties were also 
initialised (implicitly, to null). It is true that they are formally 
incompatible; when you say:

> And making the behaviour different after unset() just hides the user's 
> problem, which is that they didn't expect to *ever* have a call to __get for 
> that property.

you are referring to the expectation given by use case 1, which contradicts the 
expectation given by use case 2. However, it is not a problem in practice, 
because users of classes implementing (1) but not (2) do not unset declared 
properties, ever.

The conflict became evident with the advent of typed properties, which cannot 
be implicitly initialised to null in general. As both use cases are firmly 
rooted in practice, both should be taken in account. The current, cumbersome 
and unfortunate behaviour allows to keep sane semantics for those classes using 
bad practices (use case 1), while not invalidating naughty hacks used by other 
classes (use case 2).


—Claude

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to