[php-src] master: Merge branch 'PHP-8.5'

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-06-25T18:55:36-04:00

Commit: https://github.com/php/php-src/commit/08c6ecac52acc7911e7f607e8cc254e6c89ff4d1
Raw diff: https://github.com/php/php-src/commit/08c6ecac52acc7911e7f607e8cc254e6c89ff4d1.diff

Merge branch 'PHP-8.5'

* PHP-8.5:
  Report dynamic property shadowing a private parent in Reflection

Changed paths:
  A  ext/reflection/tests/gh22441.phpt
  M  ext/reflection/php_reflection.c


Diff:

diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index f5b1cb2010a0..00085968be79 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -4600,19 +4600,17 @@ ZEND_METHOD(ReflectionClass, hasProperty)
 	}
 
 	GET_REFLECTION_OBJECT_PTR(ce);
-	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
-		if ((property_info->flags & ZEND_ACC_PRIVATE) && property_info->ce != ce) {
-			RETURN_FALSE;
-		}
+	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL
+	 && (!(property_info->flags & ZEND_ACC_PRIVATE)
+	  || property_info->ce == ce)) {
 		RETURN_TRUE;
-	} else {
-		if (Z_TYPE(intern->obj) != IS_UNDEF) {
-			if (Z_OBJ_HANDLER(intern->obj, has_property)(Z_OBJ(intern->obj), name, ZEND_PROPERTY_EXISTS, NULL)) {
-				RETURN_TRUE;
-			}
+	}
+	if (Z_TYPE(intern->obj) != IS_UNDEF) {
+		if (Z_OBJ_HANDLER(intern->obj, has_property)(Z_OBJ(intern->obj), name, ZEND_PROPERTY_EXISTS, NULL)) {
+			RETURN_TRUE;
 		}
-		RETURN_FALSE;
 	}
+	RETURN_FALSE;
 }
 /* }}} */
 
@@ -4631,12 +4629,13 @@ ZEND_METHOD(ReflectionClass, getProperty)
 	}
 
 	GET_REFLECTION_OBJECT_PTR(ce);
-	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
-		if (!(property_info->flags & ZEND_ACC_PRIVATE) || property_info->ce == ce) {
-			reflection_property_factory(ce, name, property_info, return_value);
-			return;
-		}
-	} else if (Z_TYPE(intern->obj) != IS_UNDEF) {
+	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL
+	 && (!(property_info->flags & ZEND_ACC_PRIVATE)
+	  || property_info->ce == ce)) {
+		reflection_property_factory(ce, name, property_info, return_value);
+		return;
+	}
+	if (Z_TYPE(intern->obj) != IS_UNDEF) {
 		/* Check for dynamic properties */
 		if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj)), name)) {
 			reflection_property_factory(ce, name, NULL, return_value);
diff --git a/ext/reflection/tests/gh22441.phpt b/ext/reflection/tests/gh22441.phpt
new file mode 100644
index 000000000000..9ca3cb0eee74
--- /dev/null
+++ b/ext/reflection/tests/gh22441.phpt
@@ -0,0 +1,44 @@
+--TEST--
+GH-22441 (ReflectionClass::hasProperty()/getProperty() ignore dynamic properties shadowing a private parent property)
+--FILE--
+<?php
+
+class Base {
+    private mixed $shadow;
+    private mixed $onlyBase;
+}
+
+#[AllowDynamicProperties]
+class Child extends Base {}
+
+$o = new Child();
+$o->shadow = true;
+$o->noShadow = true;
+
+$r = new ReflectionObject($o);
+
+echo "hasProperty:\n";
+echo "shadow (dynamic over private parent): ";   var_dump($r->hasProperty('shadow'));
+echo "noShadow (plain dynamic): ";               var_dump($r->hasProperty('noShadow'));
+echo "onlyBase (private parent, no dynamic): ";  var_dump($r->hasProperty('onlyBase'));
+
+echo "\ngetProperty:\n";
+foreach (['shadow', 'noShadow', 'onlyBase'] as $name) {
+    try {
+        $p = $r->getProperty($name);
+        printf("%s: %s::\$%s\n", $name, $p->getDeclaringClass()->getName(), $p->getName());
+    } catch (ReflectionException $e) {
+        printf("%s: %s\n", $name, $e->getMessage());
+    }
+}
+?>
+--EXPECT--
+hasProperty:
+shadow (dynamic over private parent): bool(true)
+noShadow (plain dynamic): bool(true)
+onlyBase (private parent, no dynamic): bool(false)
+
+getProperty:
+shadow: Child::$shadow
+noShadow: Child::$noShadow
+onlyBase: Property Child::$onlyBase does not exist
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.