PHP:类型提示 - `Closure` 和 `Callable` 之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29730720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:32:41  来源:igfitidea点击:

PHP: Type hinting - Difference between `Closure` and `Callable`

php

提问by Dev01

I noticed that I can use either of Closureor Callableas type hint if we expected some callback function to run. For example:

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

function callFunc1(Closure $closure) {
    $closure();
}

function callFunc2(Callable $callback) {
    $callback();
}

$function = function() {
    echo 'Hello, World!';
};

callFunc1($function); // Hello, World!
callFunc2($function); // Hello, World!

Question:

题:

What's the difference here ? In other words when to use Closureand when to use CallableOR they serve the same purpose ?

这里有什么区别?换句话说,何时使用Closure和何时使用CallableOR 它们具有相同的目的?

回答by Rizier123

The difference is, that a Closuremust be an anonymous function, where callablealso can be a normal function.

不同的是,aClosure必须是匿名函数, wherecallable也可以是普通函数。

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: Closureand if you want also to allow normal functions use callableas type hint.

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

回答by Xorifelse

The main difference between them is that a closureis a classand callablea type.

它们之间的主要区别在于 aclosure是一个callable一个类型

The callabletype accepts anything that can be called:

callable类型接受可以调用的任何内容:

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

Where a closurewill onlyaccept an anonymous function. Note that in PHP version 7.1 you can convert functions to a closure like so: Closure::fromCallable('functionName').

closure接受了一个匿名函数。请注意,在PHP 7.1版,您可以函数转换为封闭,像这样: Closure::fromCallable('functionName')



Example:

例子:

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
}

So why use a closureover callable?

那么为什么要使用closureovercallable呢?

Strictness because a closureis 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.

严格是因为 aclosure是一个对象,它有一些额外的方法: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

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.

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

On a side note:The closureclass cannot be extended as its final.

在一个侧面说明:closure类不能扩展为最终

回答by Rod Elias

It's worth mentioning that this won't work for PHP versions 5.3.21 to 5.3.29.

值得一提的是,这不适用于 PHP 版本 5.3.21 到 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.

你好,世界!可捕获的致命错误:传递给 callFunc2() 的参数 1 必须是 > Callable 的实例,给定的闭包实例,在第 16 行的 /in/kqeYD 中调用并在第 7 行的 /in/kqeYD 中定义

进程退出,代码为 255。

One can try that out using https://3v4l.org/kqeYD#v5321

可以使用https://3v4l.org/kqeYD#v5321尝试一下

Best regards,

此致,