我注意到如果我们期望一些回调函数运行,我可以使用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!
Run Code Online (Sandbox Code Playgroud)
题:
这有什么区别?换句话说,何时使用Closure以及何时使用CallableOR它们的用途相同?
Riz*_*123 147
区别在于,a 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!
Run Code Online (Sandbox Code Playgroud)
因此,如果您只想键入提示匿名函数使用:Closure并且如果您还希望允许普通函数callable用作类型提示.
Xor*_*lse 53
它们之间的主要区别在于,closure是一个阶级和callable一个类型.
该callable类型接受任何可以调用的东西:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Run Code Online (Sandbox Code Playgroud)
凡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
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
您不希望在正常函数上调用方法,因为这会引发致命错误.所以为了规避你必须写下这样的东西:
if($cb instanceof \Closure){}
Run Code Online (Sandbox Code Playgroud)
要做到这一点,每次检查都是毫无意义的.所以如果你想使用那些方法声明参数是a closure.否则只需使用正常callback.这条路; 函数调用而不是代码引发错误,导致它更容易诊断.
在一个侧面说明:本closure类不能扩展为最终.