我注意到如果我们期望运行一些回调函数,我可以使用Closure
或Callable
作为类型提示。例如:
function callFunc1(Closure $closure) {
$closure();
}
function callFunc2(Callable $callback) {
$callback();
}
$function = function() {
echo 'Hello, World!';
};
callFunc1($function); // Hello, World!
callFunc2($function); // Hello, World!
问题:
这里的区别是什么?换句话说,何时使用Closure
以及何时使用Callable
或者它们是出于同样的目的?
答案 0 :(得分:129)
不同之处在于,Closure
必须是匿名函数,其中callable
也可以是正常函数。
你可以通过下面的例子看到/测试这个,你会发现第一个会出错:
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!
因此,如果您只想输入提示匿名函数,请使用:Closure
如果您还想允许普通函数使用callable
作为类型提示。
答案 1 :(得分:42)
它们之间的主要区别在于closure
是类而callable
是类型。
callable
类型接受任何可以called的内容:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
closure
只 接受匿名函数。请注意,在PHP 7.1版中,您可以将函数转换为闭包,如下所示:
Closure::fromCallable('functionName')
namespace foo{
class bar{
private $val = 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
而不是callable
?严格,因为closure
是一个包含其他方法的对象:call()
,bind()
和bindto()
。它们允许您使用在类外部声明的函数,并像在类中一样执行它。
$inject = function($i){return $this->val * $i;};
$cb1 = Closure::bind($inject, $fb);
$cb2 = $inject->bindTo($fb);
echo $cb1->call($fb, 2); // 20
echo $cb2(3); // 30
您不希望在正常函数上调用方法,因为这会引发致命错误。所以为了规避你必须写下这样的东西:
if($cb instanceof \Closure){}
每次检查都是毫无意义的。因此,如果您想使用这些方法声明参数是closure
。否则只需使用普通callback
。这条路;函数调用而不是代码引发错误,导致它更容易诊断。
旁注: closure
类无法扩展为final。
答案 2 :(得分:-1)
值得一提的是,这不适用于PHP版本5.3.21到5.3.29。
在任何这些版本中,您都会获得如下输出:
你好,世界! 可捕获的致命错误:传递给callFunc2()的参数1必须是>的实例可调用的Closure实例,在第16行的/ in / kqeYD中调用,在第7行的/ in / kqeYD中定义
使用代码255退出流程。
可以尝试使用https://3v4l.org/kqeYD#v5321
致以最诚挚的问候,