diff --git a/UPGRADING b/UPGRADING index f82aad3f8b3c..a4cc44f9a004 100644 --- a/UPGRADING +++ b/UPGRADING @@ -476,6 +476,17 @@ 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 + . 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 ReflectionExtension::getClassNames() instead. diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0b1c458db080..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) { @@ -5919,6 +5933,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); @@ -6046,6 +6069,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/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 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" +} 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"