Skip to content

Commit edc53a4

Browse files
committed
Properly handle lazy objects
1 parent cbd9d8f commit edc53a4

4 files changed

Lines changed: 115 additions & 2 deletions

File tree

ext/reflection/php_reflection.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6676,8 +6676,20 @@ ZEND_METHOD(ReflectionProperty, isReadable)
66766676

66776677
zend_class_entry *ce = obj ? obj->ce : intern->ce;
66786678
if (!prop) {
6679-
if (obj && obj->properties && zend_hash_find_ptr(obj->properties, ref->unmangled_name)) {
6680-
RETURN_TRUE;
6679+
if (obj) {
6680+
/* __isset call needs to happen on lazy object, so copy obj. */
6681+
zend_object *instance = obj;
6682+
retry_dynamic:
6683+
if (zend_lazy_object_must_init(instance)) {
6684+
instance = zend_lazy_object_init(instance);
6685+
if (!instance) {
6686+
RETURN_THROWS();
6687+
}
6688+
goto retry_dynamic;
6689+
}
6690+
if (instance->properties && zend_hash_find_ptr(instance->properties, ref->unmangled_name)) {
6691+
RETURN_TRUE;
6692+
}
66816693
}
66826694
handle_magic_get:
66836695
if (ce->__get) {
@@ -6717,8 +6729,16 @@ ZEND_METHOD(ReflectionProperty, isReadable)
67176729
RETURN_FALSE;
67186730
}
67196731
} else if (obj && (!prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET])) {
6732+
retry_declared:;
67206733
zval *prop_val = OBJ_PROP(obj, prop->offset);
67216734
if (Z_TYPE_P(prop_val) == IS_UNDEF) {
6735+
if (zend_lazy_object_must_init(obj) && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
6736+
obj = zend_lazy_object_init(obj);
6737+
if (!obj) {
6738+
RETURN_THROWS();
6739+
}
6740+
goto retry_declared;
6741+
}
67226742
if (!(Z_PROP_FLAG_P(prop_val) & IS_PROP_UNINIT)) {
67236743
goto handle_magic_get;
67246744
}
@@ -6801,7 +6821,17 @@ ZEND_METHOD(ReflectionProperty, isWritable)
68016821
RETURN_FALSE;
68026822
}
68036823
} else if (obj && (prop->flags & ZEND_ACC_READONLY)) {
6824+
retry:;
68046825
zval *prop_val = OBJ_PROP(obj, prop->offset);
6826+
if (Z_TYPE_P(prop_val) == IS_UNDEF
6827+
&& zend_lazy_object_must_init(obj)
6828+
&& (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
6829+
obj = zend_lazy_object_init(obj);
6830+
if (!obj) {
6831+
RETURN_THROWS();
6832+
}
6833+
goto retry;
6834+
}
68056835
if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) {
68066836
RETURN_FALSE;
68076837
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Test ReflectionProperty::isReadable() lazy
3+
--CREDITS--
4+
Arnaud Le Blanc (arnaud-lb)
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
public int $a;
10+
public int $b;
11+
12+
public function __construct() {
13+
$this->a = 1;
14+
}
15+
}
16+
17+
$rc = new ReflectionClass(A::class);
18+
$obj = $rc->newLazyProxy(fn() => new A());
19+
20+
$rp = new ReflectionProperty(A::class, 'a');
21+
var_dump($rp->isReadable(null, $obj));
22+
23+
$rp = new ReflectionProperty(A::class, 'b');
24+
var_dump($rp->isReadable(null, $obj));
25+
26+
?>
27+
--EXPECT--
28+
bool(true)
29+
bool(false)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Test ReflectionProperty::isReadable() lazy dynamic
3+
--CREDITS--
4+
Arnaud Le Blanc (arnaud-lb)
5+
--FILE--
6+
<?php
7+
8+
#[AllowDynamicProperties]
9+
class A {
10+
public $_;
11+
12+
public function __construct() {
13+
$this->prop = 1;
14+
}
15+
}
16+
17+
$rc = new ReflectionClass(A::class);
18+
$obj = $rc->newLazyProxy(fn() => new A());
19+
20+
$rp = new ReflectionProperty(new A, 'prop');
21+
var_dump($rp->isReadable(null, $obj));
22+
23+
?>
24+
--EXPECT--
25+
bool(true)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Test ReflectionProperty::isWritable() lazy
3+
--CREDITS--
4+
Arnaud Le Blanc (arnaud-lb)
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
public public(set) readonly int $a;
10+
public public(set) readonly int $b;
11+
12+
public function __construct() {
13+
$this->a = 1;
14+
}
15+
}
16+
17+
$rc = new ReflectionClass(A::class);
18+
$obj = $rc->newLazyProxy(fn() => new A());
19+
20+
$rp = new ReflectionProperty(A::class, 'a');
21+
var_dump($rp->isWritable(null, $obj));
22+
23+
$rp = new ReflectionProperty(A::class, 'b');
24+
var_dump($rp->isWritable(null, $obj));
25+
26+
?>
27+
--EXPECT--
28+
bool(false)
29+
bool(true)

0 commit comments

Comments
 (0)