PHP - 可调用方法不是数组

时间:2015-09-08 13:41:28

标签: php callable

通常在PHP中,如果你有一个类$departments = Get-ADUser -Filter * -Property Department | Where-Object { $_.Department } | Select -Expand Department -Unique $departments | Out-File 'H:\TEST\DEPTAAAAA.csv' 的方法a = 1 f = fn new_a when a === new_a -> true _ -> false end 并且你想将它传递给一个可调用的,你可以使用像

这样的东西
bar

这样做的缺点是Foo评估为$foo = new Foo(); $callable = [$foo, 'bar'];

是否有另一种可行的方法可以将类方法作为可调用方传递,以便is_array($callable)返回true

3 个答案:

答案 0 :(得分:10)

是的,有......虽然这是一个可怕的,可怕的黑客:

$foo = new Foo();

function makeCallable($instance, $method)
{
    return function() use ($instance, $method) {
        return $instance->{$method}();//use func_get_args + call_user_func_array to support arguments
    };
}

然后你可以使用:

$callable = makeCallable($foo, 'bar');
var_dump(is_array($callable));//false

缺点是:

var_dump($callbale instanceof Closure);//true

基本上,不要注意你的callable也是一个数组,只需在整个代码库中使用type-hinting:

function foobar(callable $action)
{
    return call_user_func($action);
}

应该工作得很好。

为什么你觉得当前的可调用数组是一个缺点:我理解为什么你觉得这不是一件好事。确实没有必要让任何人知道特定的可调用构造是一个数组,一个字符串,或一个匿名函数(实际上是Closure类的一个实例 - 你可能不想传递的另一个实现细节周围)。但这正是因为可调用的构造有多种形式,callable类型提示存在:你编写的代码需要一个可调用的需要不关心如何实现可调用的实体,它只需要知道它可以打电话给那条信息:

function handleEvent(callable $action, array $args = null)
{
    if ($args) {
        return call_user_func_array($action, $args);
    }
    return call_user_fun($action);
}

我无需检查$action是否为字符串(如'strtolower'Closure实例或数组)我只是知道我可以调用它

答案 1 :(得分:4)

PHP中的函数和方法不是一等公民,即它们不能分配给变量,没有类型等。

callable实际上并不是一种类型,is_callable以及callable类型提示只是检查某些内容是否可以用作函数 。这可以是:

  • 静态方法的数组[class, method]
  • 实例方法的数组[object, method]
  • 函数的字符串
  • 一个Closure实例
  • 实现魔术方法__invoke()
  • 的对象

如您所见,所有这些值实际上都有不同的类型,恰好可以"可调用"。没有"纯粹的"可调用的,没有其他类型。

答案 2 :(得分:1)

PHP 7.1最终通过Closure :: fromCallable(RFC)使回调成为一等公民。

here所述,您可以像这样使用它:

class MyClass
{
  public function getCallback() {
    return Closure::fromCallable([$this, 'callback']);
  }

  public function callback($value) {
    echo $value . PHP_EOL;
  }
}

$callback = (new MyClass)->getCallback();
$callback('Hello World');

使用它有一些好处:

  • 更好的错误处理-使用Closure :: fromCallable时,它在正确的位置显示错误,而不是在我们使用可调用的位置显示错误。这使调试容易得多。

  • 包装范围-即使回调是MyClass的私有/受保护方法,上面的示例也可以正常工作。

  • 性能-通过避免检查给定可调用项是否确实是可调用项的开销,这也可以提高性能。