Skip to content

Commit 31130cc

Browse files
committed
WIP: Handle magic methods and call __isset
1 parent 15c28c2 commit 31130cc

9 files changed

+311
-181
lines changed

ext/reflection/php_reflection.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6639,10 +6639,6 @@ static zend_result get_ce_from_scope_name(zend_class_entry **scope, zend_string
66396639
*scope = NULL;
66406640
return SUCCESS;
66416641
}
6642-
if (zend_string_equals(scope_name, ZSTR_KNOWN(ZEND_STR_STATIC))) {
6643-
*scope = EX(prev_execute_data)->func->common.scope;
6644-
return SUCCESS;
6645-
}
66466642

66476643
*scope = zend_lookup_class(scope_name);
66486644
if (!*scope) {
@@ -6726,10 +6722,25 @@ ZEND_METHOD(ReflectionProperty, isReadable)
67266722
}
67276723
}
67286724

6729-
if (obj) {
6725+
if (obj && !prop->hooks) {
67306726
zval *prop_val = OBJ_PROP(obj, prop->offset);
6731-
if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) {
6732-
RETURN_FALSE;
6727+
if ( Z_TYPE_P(prop_val) == IS_UNDEF) {
6728+
if (!obj->ce->__get || (Z_PROP_FLAG_P(prop_val) & IS_PROP_UNINIT)) {
6729+
RETURN_FALSE;
6730+
}
6731+
if (obj->ce->__isset) {
6732+
uint32_t *guard = zend_get_property_guard(obj, ref->unmangled_name);
6733+
if (!((*guard) & ZEND_GUARD_PROPERTY_ISSET)) {
6734+
GC_ADDREF(obj);
6735+
*guard |= ZEND_GUARD_PROPERTY_ISSET;
6736+
zval member;
6737+
ZVAL_STR(&member, ref->unmangled_name);
6738+
zend_call_known_instance_method_with_1_params(obj->ce->__isset, obj, return_value, &member);
6739+
*guard &= ~ZEND_GUARD_PROPERTY_ISSET;
6740+
OBJ_RELEASE(obj);
6741+
return;
6742+
}
6743+
}
67336744
}
67346745
}
67356746

ext/reflection/tests/ReflectionProperty_isReadable.phpt

Lines changed: 0 additions & 84 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
Test ReflectionProperty::isReadable() hooks
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $a { get => $this->a; }
8+
public $b { get => 42; }
9+
public $c { set => $value; }
10+
public $d { set {} }
11+
public $e { get => $this->e; set => $value; }
12+
public $f { get {} set {} }
13+
}
14+
15+
$test = static function ($scope) {
16+
$rc = new ReflectionClass(A::class);
17+
foreach ($rc->getProperties() as $rp) {
18+
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
19+
var_dump($rp->isReadable(null, $scope));
20+
}
21+
};
22+
23+
$test('A');
24+
$test(null);
25+
26+
?>
27+
--EXPECT--
28+
a from A: bool(true)
29+
b from A: bool(true)
30+
c from A: bool(true)
31+
d from A: bool(false)
32+
e from A: bool(true)
33+
f from A: bool(true)
34+
a from global: bool(true)
35+
b from global: bool(true)
36+
c from global: bool(true)
37+
d from global: bool(false)
38+
e from global: bool(true)
39+
f from global: bool(true)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
--TEST--
2+
Test ReflectionProperty::isReadable() init
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $a;
8+
public int $b;
9+
public int $c = 42;
10+
public int $d;
11+
public int $e;
12+
13+
public function __construct() {
14+
unset($this->e);
15+
}
16+
}
17+
18+
class B {
19+
public int $f;
20+
public int $g;
21+
public int $h;
22+
23+
public function __construct() {
24+
unset($this->g);
25+
unset($this->h);
26+
}
27+
28+
public function __isset($name) {
29+
return $name === 'h';
30+
}
31+
32+
public function __get($name) {}
33+
}
34+
35+
class C {
36+
public int $i;
37+
public int $j;
38+
public int $k;
39+
40+
public function __construct() {
41+
unset($this->j);
42+
unset($this->k);
43+
}
44+
45+
public function __get($name) {}
46+
}
47+
48+
$test = static function ($class) {
49+
$rc = new ReflectionClass($class);
50+
foreach ($rc->getProperties() as $rp) {
51+
echo $rp->getName() . ' from global: ';
52+
var_dump($rp->isReadable(new $class, NULL));
53+
}
54+
};
55+
56+
$test('A');
57+
$test('B');
58+
$test('C');
59+
60+
?>
61+
--EXPECT--
62+
a from global: bool(true)
63+
b from global: bool(false)
64+
c from global: bool(true)
65+
d from global: bool(false)
66+
e from global: bool(false)
67+
f from global: bool(false)
68+
g from global: bool(false)
69+
h from global: bool(true)
70+
i from global: bool(false)
71+
j from global: bool(true)
72+
k from global: bool(true)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Test ReflectionProperty::isReadable() visibility
3+
--FILE--
4+
<?php
5+
6+
class A {}
7+
8+
class B extends A {
9+
public $a;
10+
protected $b;
11+
private $c;
12+
public protected(set) int $d;
13+
}
14+
15+
class C extends B {}
16+
17+
$test = static function ($scope) {
18+
$rc = new ReflectionClass(B::class);
19+
foreach ($rc->getProperties() as $rp) {
20+
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
21+
var_dump($rp->isReadable(null, $scope));
22+
}
23+
};
24+
25+
foreach (['A', 'B', 'C'] as $scope) {
26+
$test($scope);
27+
}
28+
$test(null);
29+
30+
?>
31+
--EXPECT--
32+
a from A: bool(true)
33+
b from A: bool(true)
34+
c from A: bool(false)
35+
d from A: bool(true)
36+
a from B: bool(true)
37+
b from B: bool(true)
38+
c from B: bool(true)
39+
d from B: bool(true)
40+
a from C: bool(true)
41+
b from C: bool(true)
42+
c from C: bool(false)
43+
d from C: bool(true)
44+
a from global: bool(true)
45+
b from global: bool(false)
46+
c from global: bool(false)
47+
d from global: bool(true)

ext/reflection/tests/ReflectionProperty_isWritable.phpt

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)