类型提示——\`Closure\` 和 \`Callable\` 的区别

新手上路,请多包涵

我注意到我可以使用 ClosureCallable 作为类型提示,如果我们希望运行一些回调函数的话。例如:

 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 还是 它们的目的相同?

原文由 Dev01 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 637
2 个回答

区别在于,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!

因此,如果您只想键入提示匿名函数,请使用: Closure 如果您还想允许普通函数使用 callable 作为类型提示。

原文由 Rizier123 发布,翻译遵循 CC BY-SA 3.0 许可协议

它们之间的主要区别是 a closure 是一个 classcallable 是一个 type

callable 类型接受任何可以 调用 的东西:

 var_dump(
  is_callable('functionName'),
  is_callable([$myClass, 'methodName']),
  is_callable(function(){})
); // all true

其中 closure 接受匿名函数。请注意,在 PHP 7.1 版中,您可以像这样将函数转换为闭包: 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 而不是 callable 呢?

Strictness because a closure is an object that has some additional methods: call() , bind() and bindto() .它们允许您使用在类外部声明的函数并像在类内部一样执行它:

 $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

您不希望在普通函数上调用方法,因为那样会引发致命错误。因此,为了避免这种情况,您必须编写如下内容:

 if($cb instanceof \Closure){}

每次都做这个检查是没有意义的。因此,如果您想使用这些方法,请声明参数是 closure 。否则只需使用普通的 callback 。这边走;函数调用而不是您的代码会引发错误,导致它更容易诊断。

附带说明: closure 类不能扩展为它的 最终.

原文由 Xorifelse 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏