PHP 8.2: Partially-supported callable are deprecated

Version8.2
TypeDeprecation

PHP 8.2 deprecates certain patterns of callables that do not work with the $callable() pattern.

PHP supports several forms to create a callable. A callable can then be called with or without parameters using $callable() syntax, user_call_func(/_array), or by passing it to PHP function that calls back a given callback.

Unaffected Callable Patterns

$callable = 'strlen';
$callable = ['MyClass', 'myMethod'];
$callable = 'MyClass::myMethod'];
$callable = Closure::fromCallable();
$callable = [$this, 'myMethod'];
$callable = [new MyClass(), 'myMethod'];
$callable = strlen(...);

$callable = strlen(...); example above uses First-class callable syntax added in PHP 8.1.

All of the patterns of creating a callable are compatible with $callable() syntax, user_call_func(/_array) functions, and passing to a function expects a callable.

All of them also return true for is_callable, and are accepted for callable parameter/return type.

Deprecated Callable Patterns

Currently, there are some forms of creating callables that are not consistent when it is used:

$callable = "self::method";
$callable = "parent::method";
$callable = "static::method";
$callable = ["self", "method"];
$callable = ["parent", "method"];
$callable = ["static", "method"];
$callable = ["MyClass", "MyParentClass::myMethod"];
$callable = [new MyClass(), "MyOtherClass::myMethod"];

All of the patterns above are considered valid callable values for the callable type and is_callable function. Further, they are also accepted by user_call_func(/_array) functions and functions that accept a callable.


These callable patterns are inconsistent, as in they are not supported by the $callable($params) calling pattern. In PHP 8.2 and later, calling such callable emits a deprecation notice:

class Test {
    public static function myMethod(): void {
        echo "Called";
    }

    public static function call(): void {
        $callable = 'self::myMethod';
        call_user_func($callable);
    }
}

$callable = Test::call();
// "Called";

The self::myMethod callable is not it was called with $callable() pattern:

Error: Class "self" not found in ... on line ...

However, call_user_func, call_user_func_array, and internal functions that accept a callable (such as array_map) allow this pattern. In PHP 8.2 and later, calling such callable emits a deprecation notice:

Deprecated: Use of "self" in callables is deprecated in ... on line ...

All of the patterns above result in a similar deprecation notice at the time the callables are called. Passing such callables to is_callable function or using them with callable return/parameter types does not emit a deprecation notice.

Avoiding the Deprecation Notice

The easiest way to avoid the deprecation notice is to convert all self, parent, and static keywords in the callable construction to their corresponding class names. This can be easily done with the ::class magic method, which resolves to the fully-qualified class name.

 class Test {
     public static function myMethod(): void {
         echo "Called";
     }

     public static function call(): void {
-        $callable = 'self::myMethod';
+        $callable = self::class . '::myMethod';
         call_user_func($callable);
     }
 }

 $callable = Test::call();
 // "Called";

Alternately, using first-class callable syntax (added in PHP 8.1) or the array syntax might be an improvement for code clarity. Further, it is possible to use $callable() syntax, that is slightly faster because it avoids the call_user_func function call overhead:

-   $callable = 'self::myMethod';
+   $callable = self::myMethod(...);
-   call_user_func($callable);
+   $callable();    

Rationale Behind the Change

PHP supported various callable construct syntax over the years, and it now needs to account for method visibility (e.g. calling a private method from a class context) and other factors that make handling these patterns technically complex.

This deprecation also aims to reduce the context-dependability of callables such as self::myMethod, and encourage the Closure APIs, that can correctly handle the class contexts regardless of the call-site.

Instead of extending $callable() call pattern to accommodate the now-deprecated patterns, the decision was made to deprecate using these context-dependent and uncommon callable constructs with call_user_func and related functions.

$callable() is the recommended and most widely adopted calling pattern for callables, and this deprecation also encourages it.

Backwards Compatibility Impact

From PHP 8.2 and later, calling any of the callables with deprecated callable constructs emit a deprecation notice.

The easiest way to avoid this deprecation notice is to make use of ::class magic constant that resolves to the actual class name. This should work all PHP >= 5.3 versions.

On PHP 8.0 and later, it is also possible to use the ::class magic constant on class objects.

Related Changes


RFC Discussion Implementation