【问题标题】:What is the PHP7 type of a closure?什么是 PHP7 类型的闭包?
【发布时间】:2018-05-30 22:06:43
【问题描述】:

这是代码,它是一个简单的容器。

class Application
{
  private $recipes;
  private $instances;

  public function configureCache(XXXXXXXX $closure) {
    $recipes['cache'] = $closure;
  }

  public function getCache(): Cache {
    if (empty($instances['cache'])) {
      $instances['cache'] = $recipes['cache']();
    }
    return $instances['cache'];
  }
}

此代码在 PHP 7.1+ 上运行。我可以为 XXXXXXXX 填写什么以使其最具体?该类型是一个函数,更具体地说是一个返回 Cache 的函数。

【问题讨论】:

标签: php php-7 signature php-7.2


【解决方案1】:

PHP 支持多种可调用实体的语法:包含函数名称的字符串、对象和方法的数组、静态方法的类和方法数组、第一类闭包和生成的闭包。

所有这些的类型提示都是callable

如果您只需要匿名函数,即第一类闭包,请使用Closure。但这会限制您可以接受的可调用类型。

到目前为止,PHP 不支持正式可调用参数的参数提示或返回类型提示:您的代码不能说,例如,只接受带有一个字符串参数并返回布尔值的闭包。

【讨论】:

  • 我想我真正想要的是移植到 Swift 的 PHP 函数
【解决方案2】:

如果您特别想强制某人传递匿名函数,那么它将始终是the Closure class 的实例。

如果您真正想要的是“可以像函数一样使用的东西”,您可以使用callable pseudo-type,它接受闭包以及各种字符串和数组表示法来引用命名函数和方法。

您还可以使用Closure::fromCallable 将任何可调用对象转换为闭包实例。

不幸的是,你无法得到比这更具体的了;已经有建议为可调用对象提供特定签名,或者允许它们满足特制的接口定义,但目前还没有被采用。

但是,您可能需要一个使用一种方法实现普通接口的对象,我相信该方法可能是the magic __invoke method。然后调用者可以使用anonymous class 而不是匿名函数:

interface CacheFactory {
    public function __invoke(): Cache;
} 
$app->configureCache(new class implements CacheFactory {
    public function __invoke(): Cache {
          return new Cache;
    }
});

请注意,生成的对象本身会传递 callable 类型提示以及 CacheFactory,并且可以像示例中的匿名函数一样使用。

然而,即使使用此解决方案,类型也仅在运行时检查,因此此代码本身不会引发任何错误,您只会在 10% 的时间收到类型错误 当你实际运行回调时:

$app->configureCache(new class implements CacheFactory {
    public function __invoke(): Cache {
          return rand(0,10) > 9 ? "Nonsense" : new Cache;
    }
});

大多数时候,您可能只需要callable 和一些好的文档。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-11
    • 2021-01-01
    • 2017-12-12
    • 2013-07-17
    • 2018-07-05
    相关资源
    最近更新 更多