PHP 8.1 : First Class Callable support
05, November 2022

In PHP, some functions (such as call_user_func() or usort()) accept user defined functions known as callbacks. While in modern versions, php ecosystem has moved to a better alternatives called closure, callback is still supported.

But callbacks are kinda ugly. Here is the examples:

// functions as callback
echo call_user_func('strlen', 'hello world');
// 11

// class methods as callback
echo call_user_func([$this, 'methodName']); 

As we can see, callables can be stated as string or array. Which is kinda confusing when reading code and finding function usage is much harder.


However, we can convert callable to closure (which is always better) but that doesn't solve the issue much.

$closure = Closure::fromCallable('strlen'); // now we have a closure
// or
$closure = Closure::fromCallable($this, 'methodName');


PHP 8.1 adds first class callable support in the language. Now we can convert callables into closure in more elegant way.

The syntax looks as if we are calling the function/method, but in place of argument, we are using three dots (...)

 // we are not calling the strlen method, just converting to closure
$closure = strlen(...);

// now we can call the closure
$closure('something'); // 9


// we can call class method too
$closure = $object->methodName(...);

$closure('some argument'); // works


What are the three dots doing there?

The three dots are just placeholder for the arguments that the original function/method has. This allows us to convert a function to closure without redefining their arguments again.

function funcWithOneArgument($argOne) 
{
    echo 'got one';
}

function funcWithTwoArgument($argOne, $argTwo) 
{
    echo 'got two';
}

function funcWithThreeArgument($argOne, $argTwo, $argThree) 
{
    echo 'got three';
}

$closure1 = funcWithOneArgument(...); // again, not calling the function, just converting to closure
$closure2 = funcWithTwoArgument(...);
$closure3 = funcWithThreeArgument(...);

// notice how we have closures, without defining any arguments

// time to execute the closures
$closure1('arg1'); // since $closure1 is converted from funcWithOneArgument, it accepts only one argument

$closure2('arg1', 'arg2'); // got two

$closure3('arg1', 'arg2', 'arg3'); // got two

// what if we don't pass all arguments?
$closure3('arg1', 'arg2');
// PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function funcWithThreeArgument(), 2 passed and exactly 3 expected


There are multiple syntax variety for first class callable. All of the bellow syntaxt is supported:

strlen(...);
$closure(...);
$invokableObject(...);
$obj->method(...);
$obj->$methodStr(...);
($obj->property)(...);
Foo::method(...);
$classStr::$methodStr(...);
self::{$complex . $expression}(...);
'strlen'(...);
[$obj, 'method'](...);
[Foo::class, 'method'](...);


RFC: https://wiki.php.net/rfc/first_class_callable_syntax


Write comment about this article: