[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