Re: [RFC][Discussion] Harmonise "untyped" and "typed" properties

From: Date: Thu, 23 Nov 2023 09:41:56 +0000
Subject: Re: [RFC][Discussion] Harmonise "untyped" and "typed" properties
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-121775@lists.php.net to get a copy of this message
> Le 23 nov. 2023 à 08:56, Rowan Tommins <rowan.collins@gmail.com> a écrit : > > On 23 November 2023 01:37:06 GMT, Claude Pache <claude.pache@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

« previous php.internals (#121775) next »