mirror of
https://github.com/php/php-src.git
synced 2024-09-21 01:47:25 +00:00
Fix ReflectionProperty::isInitialized() for hooked props
In zend_std_has_property with ZEND_PROPERTY_EXISTS, we'd just return true when no get hook was present. However, this function is supposed to return false for uninitialized properties. PROPERTY_EXISTS is somewhat of a misnomer. Virtual properties continue to always return true, given there's no backing value to check. Fixes GH-15694 Closes GH-15822
This commit is contained in:
parent
bdcb2185aa
commit
025ed70ce3
2
NEWS
2
NEWS
@ -49,6 +49,8 @@ PHP NEWS
|
||||
- Reflection:
|
||||
. Fixed bug GH-15718 (Segfault on ReflectionProperty::get{Hook,Hooks}() on
|
||||
dynamic properties). (DanielEScherzer)
|
||||
. Fixed bug GH-15694 (ReflectionProperty::isInitialized() is incorrect for
|
||||
hooked properties). (ilutov)
|
||||
|
||||
- SOAP:
|
||||
. Fixed bug #61525 (SOAP functions require at least one space after HTTP
|
||||
|
@ -2208,6 +2208,15 @@ found:
|
||||
}
|
||||
} else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
|
||||
zend_function *get = prop_info->hooks[ZEND_PROPERTY_HOOK_GET];
|
||||
|
||||
if (has_set_exists == ZEND_PROPERTY_EXISTS) {
|
||||
if (prop_info->flags & ZEND_ACC_VIRTUAL) {
|
||||
return true;
|
||||
}
|
||||
property_offset = prop_info->offset;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (!get) {
|
||||
if (prop_info->flags & ZEND_ACC_VIRTUAL) {
|
||||
zend_throw_error(NULL, "Property %s::$%s is write-only",
|
||||
@ -2219,19 +2228,12 @@ found:
|
||||
}
|
||||
}
|
||||
|
||||
if (has_set_exists == ZEND_PROPERTY_EXISTS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
zval rv;
|
||||
if (!zend_call_get_hook(prop_info, name, get, zobj, &rv)) {
|
||||
if (EG(exception)) {
|
||||
return 0;
|
||||
}
|
||||
property_offset = prop_info->offset;
|
||||
if (!ZEND_TYPE_IS_SET(prop_info->type)) {
|
||||
prop_info = NULL;
|
||||
}
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
--TEST--
|
||||
ReflectionProperty::isInitialized() on hooked properties
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
// Plain
|
||||
public $p1;
|
||||
public string $p2;
|
||||
// Virtual
|
||||
public $v1 { get => throw new Exception(); }
|
||||
public $v2 { set { throw new Exception(); } }
|
||||
// Backed
|
||||
public $b1 { get => throw new Exception($this->b1); }
|
||||
public string $b2 { get => throw new Exception($this->b2); }
|
||||
public $b3 { set => throw new Exception(); }
|
||||
public string $b4 { set => throw new Exception(); }
|
||||
}
|
||||
|
||||
$test = new Test();
|
||||
$rc = new ReflectionClass(Test::class);
|
||||
foreach ($rc->getProperties() as $rp) {
|
||||
echo $rp->getName(), "\n";
|
||||
var_dump($rp->isInitialized($test));
|
||||
try {
|
||||
$rp->setRawValue($test, 42);
|
||||
} catch (Error $e) {}
|
||||
var_dump($rp->isInitialized($test));
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
p1
|
||||
bool(true)
|
||||
bool(true)
|
||||
p2
|
||||
bool(false)
|
||||
bool(true)
|
||||
v1
|
||||
bool(true)
|
||||
bool(true)
|
||||
v2
|
||||
bool(true)
|
||||
bool(true)
|
||||
b1
|
||||
bool(true)
|
||||
bool(true)
|
||||
b2
|
||||
bool(false)
|
||||
bool(true)
|
||||
b3
|
||||
bool(true)
|
||||
bool(true)
|
||||
b4
|
||||
bool(false)
|
||||
bool(true)
|
Loading…
Reference in New Issue
Block a user