Commit b89e0ef305b for php.net
commit b89e0ef305b3261c9b7ecfca0a975c3678cfcdd1
Author: zaaarf <me@zaaarf.foo>
Date: Fri May 15 20:10:17 2026 +0200
Fix GH-22000: Unwrap references in ReflectionProperty::isReadable() (#22025)
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 94d8bb7d149..d15445d8d35 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -6731,6 +6731,11 @@ ZEND_METHOD(ReflectionProperty, isReadable)
zval member;
ZVAL_STR(&member, ref->unmangled_name);
zend_call_known_instance_method_with_1_params(ce->__isset, obj, return_value, &member);
+
+ if (Z_TYPE_P(return_value) == IS_REFERENCE) {
+ zend_unwrap_reference(return_value);
+ }
+
*guard &= ~ZEND_GUARD_PROPERTY_ISSET;
OBJ_RELEASE(obj);
return;
diff --git a/ext/reflection/tests/gh22000.phpt b/ext/reflection/tests/gh22000.phpt
new file mode 100644
index 00000000000..aee4863e9b7
--- /dev/null
+++ b/ext/reflection/tests/gh22000.phpt
@@ -0,0 +1,61 @@
+--TEST--
+GH-22000 - Ensure __isset returning a reference is supported by ReflectionProperty::isReadable()
+--FILE--
+<?php
+class TestClass1 {
+ public int $a = 1;
+ public int $b;
+ public int $c;
+
+ public function __construct() {
+ unset($this->b);
+ unset($this->c);
+ }
+
+ public function __isset($name) {
+ return $name === 'b';
+ }
+
+ public function __get($name) {}
+}
+
+class TestClass2 {
+ public int $d;
+ public int $e;
+ public int $f;
+
+ public function __construct() {
+ unset($this->e);
+ unset($this->f);
+ }
+
+ public function &__isset($name) {
+ return $name === 'f';
+ }
+
+ public function __get($name) {}
+}
+
+
+function test($class) {
+ $rc = new ReflectionClass($class);
+ foreach ($rc->getProperties() as $rp) {
+ echo $rp->getName() . ' from global:';
+ var_dump($rp->isReadable(null, new $class));
+ }
+}
+
+test('TestClass1');
+test('TestClass2');
+?>
+--EXPECTF--
+a from global:bool(true)
+b from global:bool(true)
+c from global:bool(false)
+d from global:bool(false)
+e from global:
+Notice: Only variable references should be returned by reference in %s on line %d
+bool(false)
+f from global:
+Notice: Only variable references should be returned by reference in %s on line %d
+bool(true)