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

Reply via email to