[GIT-PULLS] [php-src] PR #22969: Resolve the effective property in ReflectionProperty lazy APIs

[email protected] (iliaal) Fri, 31 Jul 2026 13:26:52 +0000
Newsgroups php.git-pulls
Message-ID <oSEtGmT8d1L7YPRv9yKsQUftAw5k12lGUBdgvsWfuFU@main.internal.php.net>
Pull Request: https://github.com/php/php-src/pull/22969
Author: iliaal

`ReflectionProperty::skipLazyInitialization()` and isLazy() index the object with ref->prop, the property info of the reflected scope. When a child class adds hooks to a plain parent property, inheritance gives the child its own storage slot and leaves the parent slot IS_UNDEF, so a parent-scoped ReflectionProperty reads and writes the dead slot: isLazy() answers false and skipLazyInitialization() is a silent no-op. getRawValue(), setRawValue() and setRawValueWithoutLazyInitialization() already resolve the effective property through `reflection_property_get_effective_prop()`, and these two now do the same.

```php
class B { public $b = 1; }
class C extends B { public $b { get => $this->b; set => $this->b = $value; } }

$reflector = new ReflectionClass(C::class);
$obj = $reflector->newLazyGhost(function ($obj) { $obj->b = 9; });

var_dump((new ReflectionProperty(B::class, 'b'))->isLazy($obj)); // false, should be true
var_dump((new ReflectionProperty(C::class, 'b'))->isLazy($obj)); // true
```

Private parent properties still resolve to the declaring scope's slot, and static or virtual effective properties still return false or throw.