它们之间的主要区别是a closure
是一个类和callable
一个类型。
该callable
类型接受可以被称为的任何东西:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
其中a 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
over 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
类不能扩展为最终。
["Foo", "bar"]
forFoo::bar
或[$foo, "bar"]
for$foo->bar
。