Commit d3f4eada100 for php.net

commit d3f4eada1001627df6330e7606081e7ab42ca311
Author: Daniel Scherzer <daniel.e.scherzer@gmail.com>
Date:   Tue Aug 11 15:15:37 2026 -0700

    [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

diff --git a/UPGRADING b/UPGRADING
index bfc23acb0fa..a4cc44f9a00 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 426ac625a9f..07a671739f3 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 124f728052e..57f4702e07c 100644
--- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt
+++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt
@@ -65,7 +65,7 @@ abstract function foo();
 }

 ?>
---EXPECT--
+--EXPECTF--
 Non-instance:
 string(72) "Given object is not an instance of the class this method was declared in"

@@ -75,6 +75,8 @@ abstract function foo();
 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 66f3c50da02..2d35451fa94 100644
--- a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt
+++ b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt
@@ -104,6 +104,8 @@ abstract function foo();
 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 1ddf1c51c13..dd86baa9104 100644
--- a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt
+++ b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt
@@ -53,7 +53,7 @@ abstract function foo();
 }

 ?>
---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 @@ abstract function foo();
 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