From 8c44ee0dbaafe5c0ef5c70af2439258c9bdb857e Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 11 Aug 2026 14:40:47 -0700 Subject: [PATCH 1/3] [RFC] Deprecate `ReflectionProperty::setValue()` with wrong types https://wiki.php.net/rfc/deprecations_php_8_6 --- UPGRADING | 5 +++++ ext/reflection/php_reflection.c | 9 +++++++++ .../tests/ReflectionProperty_setValue_error.phpt | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/UPGRADING b/UPGRADING index f82aad3f8b3c..34e3f62c5214 100644 --- a/UPGRADING +++ b/UPGRADING @@ -476,6 +476,11 @@ PHP 8.6 UPGRADE NOTES . The mysqli_get_charset() function is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_mysqli_get_charset +- Reflection: + . Calling ReflectionProperty::setValue() with an object that is not an + instance of the class on which the property was declared is now deprecated. + RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types + - SPL: . The spl_classes() function is now deprecated, use ReflectionExtension::getClassNames() instead. diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0b1c458db080..90fa559794c1 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5919,6 +5919,15 @@ ZEND_METHOD(ReflectionProperty, setValue) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); + if (!instanceof_function(object->ce, intern->ce)) { + zend_string *method_name = get_active_function_or_method_name(); + zend_error(E_DEPRECATED, "Calling %pS() with a given object that is not an instance of the class this property was declared in is deprecated", method_name); + zend_string_release(method_name); + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + } + const zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = intern->ce; object->handlers->write_property(object, ref->unmangled_name, value, ref->cache_slot); diff --git a/ext/reflection/tests/ReflectionProperty_setValue_error.phpt b/ext/reflection/tests/ReflectionProperty_setValue_error.phpt index 287a03679e61..25dd9adae2a9 100644 --- a/ext/reflection/tests/ReflectionProperty_setValue_error.phpt +++ b/ext/reflection/tests/ReflectionProperty_setValue_error.phpt @@ -30,11 +30,13 @@ $propInfo = new ReflectionProperty('TestClass', 'pub2'); var_dump($propInfo->setValue($instanceWithNoProperties, "NewValue")); var_dump($instanceWithNoProperties->pub2); ?> ---EXPECT-- +--EXPECTF-- Protected property: string(8) "NewValue" Instance without property: + +Deprecated: Calling ReflectionProperty::setValue() with a given object that is not an instance of the class this property was declared in is deprecated in %s on line %d NULL string(8) "NewValue" From feee2c4acd0741a73c039fb0e627e7089e294963 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 11 Aug 2026 15:00:18 -0700 Subject: [PATCH 2/3] [RFC] Deprecate `ReflectionProperty::setRawValue()` with wrong types https://wiki.php.net/rfc/deprecations_php_8_6 --- UPGRADING | 3 ++ ext/reflection/php_reflection.c | 9 ++++ .../ReflectionProperty_setRawValue_error.phpt | 50 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 ext/reflection/tests/ReflectionProperty_setRawValue_error.phpt diff --git a/UPGRADING b/UPGRADING index 34e3f62c5214..bfc23acb0fab 100644 --- a/UPGRADING +++ b/UPGRADING @@ -480,6 +480,9 @@ PHP 8.6 UPGRADE NOTES . Calling ReflectionProperty::setValue() with an object that is not an instance of the class on which the property was declared is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types + . Calling ReflectionProperty::setRawValue() with an object that is not an + instance of the class on which the property was declared is now deprecated. + RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types - SPL: . The spl_classes() function is now deprecated, use diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 90fa559794c1..426ac625a9fc 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6055,6 +6055,15 @@ ZEND_METHOD(ReflectionProperty, setRawValue) Z_PARAM_ZVAL(value) } ZEND_PARSE_PARAMETERS_END(); + if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) { + zend_string *method_name = get_active_function_or_method_name(); + zend_error(E_DEPRECATED, "Calling %pS() with a given object that is not an instance of the class this property was declared in is deprecated", method_name); + zend_string_release(method_name); + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + } + zend_reflection_property_set_raw_value(ref->prop, ref->unmangled_name, ref->cache_slot, intern->ce, Z_OBJ_P(object), value); } diff --git a/ext/reflection/tests/ReflectionProperty_setRawValue_error.phpt b/ext/reflection/tests/ReflectionProperty_setRawValue_error.phpt new file mode 100644 index 000000000000..0044e447b764 --- /dev/null +++ b/ext/reflection/tests/ReflectionProperty_setRawValue_error.phpt @@ -0,0 +1,50 @@ +--TEST-- +Test ReflectionProperty::setRawValue() error cases. +--FILE-- +hooked = "Not virtual"; + } + } +} + +#[AllowDynamicProperties] +class AnotherClass { +} + +$hookedProp = new ReflectionProperty(Example::class, 'hooked'); +$nonHookedProp = new ReflectionProperty(Example::class, 'nonHooked'); + +$instance = new Example(); +$hookedProp->setRawValue($instance, "value1"); +$nonHookedProp->setRawValue($instance, "value2"); +var_dump($instance); + +$other = new AnotherClass(); +$hookedProp->setRawValue($other, "value1"); +$nonHookedProp->setRawValue($other, "value2"); +var_dump($other); +?> +--EXPECTF-- +object(Example)#%d (2) { + ["nonHooked"]=> + string(6) "value2" + ["hooked"]=> + string(6) "value1" +} + +Deprecated: Calling ReflectionProperty::setRawValue() with a given object that is not an instance of the class this property was declared in is deprecated in %s on line %d + +Deprecated: Calling ReflectionProperty::setRawValue() with a given object that is not an instance of the class this property was declared in is deprecated in %s on line %d +object(AnotherClass)#%d (2) { + ["hooked"]=> + string(6) "value1" + ["nonHooked"]=> + string(6) "value2" +} From 80c338c6c891e29fa5772d11fadaaa06a0256b6c Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 11 Aug 2026 15:15:37 -0700 Subject: [PATCH 3/3] [RFC] Deprecate `ReflectionMethod` invocation for static methods with objects `ReflectionMethod::invoke()` and `::invokeArgs()` are affected, but share implementation code and so are updated together. https://wiki.php.net/rfc/deprecations_php_8_6 --- UPGRADING | 3 +++ ext/reflection/php_reflection.c | 16 +++++++++++++++- .../ReflectionMethod_invokeArgs_error3.phpt | 4 +++- .../tests/ReflectionMethod_invoke_basic.phpt | 2 ++ .../tests/ReflectionMethod_invoke_error1.phpt | 4 +++- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/UPGRADING b/UPGRADING index bfc23acb0fab..a4cc44f9a004 100644 --- a/UPGRADING +++ b/UPGRADING @@ -483,6 +483,9 @@ PHP 8.6 UPGRADE NOTES . Calling ReflectionProperty::setRawValue() with an object that is not an instance of the class on which the property was declared is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types + . Calling ReflectionMethod::invoke() or ReflectionMethod::invokeArgs() with + an object and a static method is now deprecated. + RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionmethodinvoke_and_reflectionmethodinvokeargs_with_objects_for_static_methods - SPL: . The spl_classes() function is now deprecated, use diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 426ac625a9fc..07a671739f32 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3375,7 +3375,21 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, bool variadic * Else, we verify that the given object is an instance of the class. */ if (mptr->common.fn_flags & ZEND_ACC_STATIC) { - object = NULL; + if (object) { + zend_string *method_name = get_active_function_or_method_name(); + zend_error( + E_DEPRECATED, + "Calling %pS() for static method %pS::%pS() does not need an object parameter", + method_name, + mptr->common.scope->name, + mptr->common.function_name + ); + zend_string_release(method_name); + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + object = NULL; + } obj_ce = mptr->common.scope; } else { if (!object) { diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt index 124f728052e2..57f4702e07c0 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt @@ -65,7 +65,7 @@ try { } ?> ---EXPECT-- +--EXPECTF-- Non-instance: string(72) "Given object is not an instance of the class this method was declared in" @@ -75,6 +75,8 @@ Exception: Using $this when not in object context NULL Private method: + +Deprecated: Calling ReflectionMethod::invokeArgs() for static method TestClass::privateMethod() does not need an object parameter in %s on line %d Called privateMethod() NULL diff --git a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt index 66f3c50da027..2d35451fa94e 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt @@ -104,6 +104,8 @@ NULL Static method: ReflectionMethod::invoke() expects at least 1 argument, 0 given ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, true given + +Deprecated: Calling ReflectionMethod::invoke() for static method TestClass::staticMethod() does not need an object parameter in %s on line %d Called staticMethod() Exception: Using $this when not in object context NULL diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt index 1ddf1c51c139..dd86baa91040 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt @@ -53,7 +53,7 @@ try { } ?> ---EXPECT-- +--EXPECTF-- invoke() on a non-object: string(85) "ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, true given" @@ -61,6 +61,8 @@ invoke() on a non-instance: string(72) "Given object is not an instance of the class this method was declared in" Private method: + +Deprecated: Calling ReflectionMethod::invoke() for static method TestClass::privateMethod() does not need an object parameter in %s on line %d Called privateMethod() NULL