Hi Ilija, Thanks for having a close look at the RFC.
Le ven. 8 mai 2026 à 14:56, Ilija Tovilo <[email protected]> a écrit : > Hi Nicolas > > Thanks for your proposal. I have some unpolished thoughts. > > On Fri, May 1, 2026 at 11:38 AM Nicolas Grekas > <[email protected]> wrote: > > > > https://wiki.php.net/rfc/exists-magic-method > > From what I can tell there are two primary objectives stated in the RFC: > > 1. Solve the "null or undefined" ambiguity problem. > 2. Allow materializing properties within the "property existence > check" magic method, whether that be __isset() or __exists(), and > avoiding the __get() call that normally follows. > > As for objective 1, it seems quite odd to me that __exists() indicates > "the property is declared and may or may not be null", when is then > used for all the constructs that ask the distinct question "is the > property defined and not null?", namely for isset(), empty() (negated) > and ??. That's the question already precisely answered by __isset(). > The behavior for disagreeing __isset() and __get() methods is odd, but > IMO this is a clear userland bug. > > The other stated benefit is having the ability to check whether a > property exists even if it may be null by calling __exists() directly. > IMO the use-cases are narrow. For declared properties, there's a > slightly unconventional solution: `array_key_exists('property', > (array)$object)`. For virtual properties; fair enough. Though these > could also use hooks nowadays. > > As for objective 2, you've mentioned this is possible to implement for > __isset() but was rejected in GH-12695 due to complexity and > performance concerns. IMO a new method does not address these > concerns, it just moves them. If the __exists() method is intended to > replace __isset() long-term, then, once all code has migrated, > performance will not differ from adding the check to __isset(). [1] > Similarly, complexity for implementing the __isset() and __exists() > should be roughly equivalent. You solved the soundness issues > mentioned in the RFC by avoiding repetition of the entire function and > copying the relevant paths. I believe something similar should work > for __isset(). > > It's also worth noting the main objection in GH-12695 was to treat it > as a bug and change behavior in stable versions. > > To summarize, in my personal opinion it's better to go back to the > original idea and add another property existence check after the > __isset() call that avoids calling __get() if the property has > materialized. From what I can tell, the has_property handler will also > need the same adjustments. I don't think the stated benefits are > enough to warrant a full migration to a new method. > > Ilija > > [1] We also concluded in the issue that performance isn't a real issue > anyway. __exists() would also perform worse due to having to call > __get() to verify the value is not null. This does make sure the > functions are in agreement, at the cost of an unnecessary call for > correct code. > I would say that the two goals of the RFC are: 1. to indeed solve the "null or undefined" ambiguity problem. 2. to provide a solid primitive for true equivalence between magic properties and regular ones. About 1. it's a long standing issue for PHP objects: libs like symfony/property-access / property-info have weird edge cases both in the implementation and in the behavior that are unfixable unless PHP provides a true way to separate between "null" and "undefined". You mention hooks: those are great when the name of the properties are known ahead of time. But that doesn't help when dealing with properties that are known only at runtime. I nowadays see magic accessors as generic property hooks. It's a powerful capability offered by the engine and it should work just great - which it isn't at the moment. About 2. the canonical broken behavior is that an expression like "$foo ?? 123" MAY provide a NULL result. That's a big WTH for the type-system. I agree that it should be considered a bug if one implements such a behavior by mistake. Yet it's a foot-gun that the engine offered in the first place - and it also opens for hacks (if not cracks) of the language semantics. Something scary to me as a person engaged in making PHP better for years now. A flaw from the past worth fixing, like many others we already fixed along the years. Then yes, deprecating __isset may be considered later, separately - it's just the cost for the community that needs to be considered separately, and in a later version of PHP. You also wrote that we can fix GH-12695 by implementing the materialization check I added to __exists. It wasn't obvious to me that this would be an acceptable move. That's good to read. Yet this alone wouldn't fix my main concerns above. About the double call to __get when using `isset($o->x) ? $o->x : $y` that's indeed true. Yet it's not an issue to me: `??` is free from this issue, has exactly the same semantics and is what ppl prefer using anyway for this exact construct. In addition, __get calls usually start with a hashtable check and are thus super quick - the double-call can be made negligible in practice. Trading perf vs correctness in the case we discuss should clearly balance towards correctness, that's the point of the RFC. About `array_key_exists('prop', (array)$object)` that's of no use for magic properties so that's unrelated. I could certainly reformulate the RFC with a wording that aligns more closely with this rationale. That wouldn't change what I propose at the technical level, but that might help getting the points. Let me know. Cheers, Nicolas
