[php-src] Issue #20830: ReflectionProperty::isInitialized() should not trigger lazy object initialization
[email protected] (greg0ire)
| Newsgroups | php.bugs |
|---|---|
| Message-ID | <[email protected]> |
Issue: https://github.com/php/php-src/issues/20830
Author: greg0ire
### Description
The following code:
```php
<?php
class TestClass {
public readonly int $id;
public string $name;
}
$rc = new ReflectionClass(TestClass::class);
$obj = $rc->newLazyGhost(function($ghost) {
$rp = new ReflectionProperty(TestClass::class, 'id');
$rp->setRawValueWithoutLazyInitialization($ghost, 123);
$ghost->name = 'initialized';
echo "Ghost initialized\n";
});
echo "Created lazy ghost\n";
echo "Is uninitialized: " . ($rc->isUninitializedLazyObject($obj) ? 'yes' : 'no') . "\n";
// Checking if a readonly property is initialized should NOT trigger initialization
$rp = new ReflectionProperty(TestClass::class, 'id');
echo "Checking ReflectionProperty::isInitialized()...\n";
$result = $rp->isInitialized($obj);
echo "isInitialized returned: " . ($result ? 'true' : 'false') . "\n";
echo "Is still uninitialized: " . ($rc->isUninitializedLazyObject($obj) ? 'yes' : 'no') . "\n";
```
Resulted in this output:
```
Created lazy ghost
Is uninitialized: yes
Checking ReflectionProperty::isInitialized()...
Ghost initialized
isInitialized returned: true
Is still uninitialized: no
```
But I expected this output instead:
```
Created lazy ghost
Is uninitialized: yes
Checking ReflectionProperty::isInitialized()...
isInitialized returned: false
Is still uninitialized: yes
```
Note: I couldn't find any discussion about this, so maybe it's an oversight. However the Lazy Objects RFC (https://wiki.php.net/rfc/lazy-objects) explicitly states under "Initialization Triggers":
> Except for the special cases listed below, any attempt to observe the state of a lazy object will trigger its initialization. This ensures that the result of the observation is the same as if the object were already initialized, maintaining full transparency.
>
> These triggers include, but are not limited to:
> - Reading or writing a property
> - Testing if a property is set or unsetting it
> - Calling ReflectionProperty::get[Raw]Value() and set[Raw]Value()
> - Calling ReflectionObject::getProperties() or ReflectionObject::getProperty()
`isInitialized()` is not listed, so it's unclear whether this is intentional or not.
For more context about this, see https://github.com/doctrine/orm/issues/12166
### PHP Version
```plain
PHP 8.4.16 (cli) (built: Dec 16 2025 16:03:34) (NTS gcc x86_64)
Copyright (c) The PHP Group
Built by Fedora Project
Zend Engine v4.4.16, Copyright (c) Zend Technologies
```
### Operating System
Fedora