Hi Tim,
Le ven. 29 mai 2026 à 12:01, Tim Düsterhus <[email protected]> a écrit :
> Hi
>
> Am 2026-05-09 15:14, schrieb Nicolas Grekas:
> >> […]
> >> need the same adjustments. I don't think the stated benefits are
> >> enough to warrant a full migration to a new method.
> >> […]
> >
> > […]
>
> I now finally got around to reading your RFC in-depth and have also read
> through the related GH-12695 issue to get the full picture.
>
> I share Ilija's opinion in that this feels very much like a
> “sledgehammer to crack a nut” approach to fix something that is
> effectively the result of a userland implementation error in a feature
> that nowadays has better replacements in many situations: Namely
> forgetting to implement `__isset()` when `__get()` is implemented; and
> not implementing a `null` check in `__isset()`. In fact the first issue
> would not be solved by the proposal, since instead of forgetting to
> implement `__isset()`, folks would just forget to implement
> `__exists()`.
>
> Given that the RFC can naturally only ship in a new PHP version and
> users will not upgrade right-away, it will take years until folks can
> actually rely on the updated behavior and they will need to maintain
> their existing workarounds until then. Specifically for the “lazy
> proxies” use case that also was the motivation for GH-12695 my
> understanding is that this is already solved in a much cleaner way since
> PHP 8.4 with native lazy objects. Why would I want to wait for PHP 8.6
> to be the baseline, when the better solution is already available with
> 8.4? Similarly other “lazy initialization” use cases for individual
> properties can already be solved with property hooks in a cleaner way.
>
> That leaves the “JsonRecord” use case, where the magic method doesn't do
> anything by itself either, since folks would need to manually call it to
> make the “exists but is null” distinction. It could just be a regular
> method there - as already done in userland collection classes that just
> have explicit `->has()` and `->get()` methods instead of relying on
> magic methods. These notably also allow for much cleaner access to
> fields that are not valid PHP identifiers (e.g. fields starting with a
> digit or fields containing spaces).
>
> I would treat this as a documentation issue, where it's not clearly
> specified that users are expected to implement a `null` check in
> `__isset()` and that users are expected to also implement `__isset()`
> when implementing `__get()`. Perhaps the latter could even be made a
> warning. That leaves the issue in GH-12695 which could then be fixed as
> a master-only bugfix. While this would still require folks to carry
> their workarounds until they can rely on PHP 8.6, it would not make the
> language any more complex by requiring folks to learn yet another
> pattern.
>
Thanks for the review.
Treating magic accessors as legacy conflicts with how widely-used PHP code
actually works: Laravel Eloquent is built on __get/__set, and a long tail
of infrastructure sits on the same primitive, with legitimate use of them
(runtime-discovered properties typically).
Also: Native lazy objects don't cover laziness on userland subclasses of
internal classes, nor interface-based proxies or decorator patterns where
the target shape is dynamic.
Property hooks need declared property names, which is the constraint that
will continue to drive users to magic accessors in the first place.
If we agree magic accessors stay load-bearing (the alternative would be a
deprecation path that nobody is proposing), fixing their broken documented
semantics is maintainer responsibility.
The underlying issue isn't a userland implementation error: even
a perfectly null-checking __isset cannot distinguish "set to null"
from "missing" on a magic property.
The method returns one bit and is being asked two questions.
The `??` RFC also explicitly defines `$x ?? $y` as `isset($x) ? $x : $y`.
That contract is currently broken on magic properties. Documentation can't
fix a contract; the engine has to.
Patching __isset for GH-12695 alone doesn't restore it either; it would
need to change isset() semantics, a universal BC break.
On "people will just forget __exists": a class with only __get() today
produces broken isset() (always false) and empty() (always true).
Adding `__exists() { return true; }` fixes both for free. The "Recommended
floor for classes with __get" section in the RFC walks through this.
It is strictly less work than the existing __get + __isset pattern.
The "->has() / ->get() methods" suggestion is missing the point by
abandoning property syntax, which is the reason magic accessors exist in
the first place.
About __get-without-__isset (nor __exists), a warning could be fine to me
as an adjacent diagnostic.
I'd defer this to a follow up RFC, because this needs its own impact
analysis and is something related yet separate.
On the master-only property-materialization fix: as I noted to Ilija, I'm
fine with decoupling it from this RFC.
The remaining motivations (the structural ambiguity, the
documented-contract violation, the early-adoption convention via
method_exists()) stand on their own.
On the timeline concern: on PHP 8.5 and earlier, __exists() is a regular
method, so libraries can already probe method_exists($obj, '__exists') and
dispatch through it as a convention today. Adoption doesn't have to wait
for PHP 8.6 to be universally deployed.
Cheers,
Nicolas