I noticed that I can use either of Closure
or Callable
as type hint if we expected some callback function to run. For example:
func
The difference is, that a Closure must be an anonymous function, where callable also can be a normal function.
You can see/test this with the example below and you will see that you will get an error for the first one:
function callFunc1(Closure $closure) {
$closure();
}
function callFunc2(Callable $callback) {
$callback();
}
function xy() {
echo 'Hello, World!';
}
callFunc1("xy"); // Catchable fatal error: Argument 1 passed to callFunc1() must be an instance of Closure, string given
callFunc2("xy"); // Hello, World!
So if you only want to type hint anonymous function use: Closure
and if you want also to allow normal functions use callable
as type hint.
It's worth mentioning that this won't work for PHP versions 5.3.21 to 5.3.29.
In any of those versions you will get an output like:
Hello, World! Catchable fatal error: Argument 1 passed to callFunc2() must be an instance of > Callable, instance of Closure given, called in /in/kqeYD on line 16 and defined in /in/kqeYD on line 7
Process exited with code 255.
One can try that out using https://3v4l.org/kqeYD#v5321
Best regards,
The main difference between them is that a closure is a class and callable a type.
The callable
type accepts anything that can be called:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
); // all true
Where a closure
will only accept an anonymous function. Note that in PHP version 7.1 you can convert functions to a closure like so:
Closure::fromCallable('functionName').
namespace foo{
class bar{
private $baz = 10;
function myCallable(callable $cb){$cb()}
function myClosure(\Closure $cb){$cb()} // type hint must refer to global namespace
}
function func(){}
$cb = function(){};
$fb = new bar;
$fb->myCallable(function(){});
$fb->myCallable($cb);
$fb->myCallable('func');
$fb->myClosure(function(){});
$fb->myClosure($cb);
$fb->myClosure(\Closure::fromCallable('func'));
$fb->myClosure('func'); # TypeError
}
closure
over callable
?Strictness because a closure
is an object that has some additional methods: call(), bind() and bindto(). They allow you to use a function declared outside of a class and execute it as if it was inside a class:
$inject = function($i){return $this->baz * $i;};
$cb1 = \Closure::bind($inject, $fb);
$cb2 = $inject->bindTo($fb);
echo $cb1->call($fb, 2); // 20
echo $cb2(3); // 30
You would not like to call methods on a normal function as that will raise fatal errors. So in order to circumvent that you would have to write something like:
if($cb instanceof \Closure){}
To do this check every time is pointless. So if you want to use those methods state that the argument is a closure
. Otherwise just use a normal callback
. This way; An error is raised on function call instead of your code causing it making it much easier to diagnose.
On a side note: The closure
class cannot be extended as its final.