如何使用 PHPDoc 对 Callable 的参数进行类型提示?

Posted

技术标签:

【中文标题】如何使用 PHPDoc 对 Callable 的参数进行类型提示?【英文标题】:How can I use PHPDoc to type-hint the parameters of a Callable? 【发布时间】:2012-11-18 21:48:33 【问题描述】:

我有一个接受回调作为参数的方法。我想在 phpDoc 中为 class method 提供一个签名,该签名概述了要传递给该方法的 callback function 的参数,以便我的 IDE (PHPStorm) 可以为传递给我的方法的函数生成有效的类型提示,或者至少查看代码的人可以确定他们打算提供的回调的签名。

例如:

class Foo 
  public $items = [];
  /**
  * @param Callable(
  *   @param ArrayObject $items The list of items that bar() will return
  * ) $baz A callback to receive the items
  **/
  public function bar(Callable $baz) 
    $items = new ArrayObject($this->items);
    $baz($items);
  

方法bar有一个参数$baz,它是一个回调函数。作为参数传递给bar() 的任何函数都必须接受ArrayObject 作为其唯一参数。

理想情况下,Callable 应该可以包含多个参数,就像任何其他方法一样。

当我编写以下代码时:

$foo = new Foo();
$foo->bar(function(

...然后我应该会收到一个参数列表,该列表正确提示了此函数调用所接受参数的类型 (ArrayObject)。

这样的事情可能吗? PHPStorm 或其他 IDE 是否支持它?即使没有 IDE 支持,是否有推荐/标准的记录方式?

【问题讨论】:

NetBeans 似乎可以应付(如果我理解你的意思):netbeans.org 【参考方案1】:

PHP 7+:

将可调用接口与匿名类结合使用就可以解决问题。它不是很方便,并且会导致类消费者的代码过于复杂,但目前它是静态代码分析方面的最佳解决方案。

/**
 * Interface MyCallableInterface
 */
interface MyCallableInterface
    /**
     * @param Bar $bar
     *
     * @return Bar
     */
    public function __invoke(Bar $bar): Bar;


/**
 * Class Bar
 */
class Bar
    /**
     * @var mixed
     */
    public $data = null;


/**
 * Class Foo
 */
class Foo
    /**
     * @var Bar
     */
    private $bar = null;

    /**
     * @param MyCallableInterface $fn
     *
     * @return Foo
     */
    public function fooBar(MyCallableInterface $fn): Foo
        $this->bar = $fn(new Bar);
        return $this;
    


/**
 * Usage
 */
(new Foo)->fooBar(new class implements MyCallableInterface
    public function __invoke(Bar $bar): Bar
        $bar->data = [1, 2, 3];
        return $bar;
    
);

如果您使用的是 PhpStorm,它甚至会在匿名类中自动生成 __invoke-Method 的签名和正文。

【讨论】:

wiki.php.net/rfc/functional-interfaces 这个 RFC 本来可以做得更好,但它被投票反对 22:6。我不知道为什么。【参考方案2】:

我通过使用callable 在类中定义static function 克服了这个问题。该函数有自己的文档块,我只是在需要使用 PHPDoc 的 @see 标记调用的方法中引用它。

class Foo

    /**
     * Description of the "bar" callable. Used by @see baz().
     *
     * @param int $index A 1-based integer.
     * @param string $name A non-empty string.
     * @return bool
     * @see baz()
     * @throws \Exception This is a prototype; not meant to be called directly.
     */
    public static barCallable($index, $name)
    
        throw new \Exception("barCallable prototype called");
    

    /**
     * Description of the baz() method, using a @see barCallable().
     *
     * @param callable $bar A non-null @see barCallable().
     * @see barCallable()
     */
    public function baz(callable $bar)
    
        // ...
        call_user_func($bar, 1, true);
        // ...
    

这在 PhpStorm 10 中运行良好。快速文档允许轻松地从方法文档导航到原型文档。

我让我的原型函数抛出一个异常,以明确它不应该被调用。我可以使用protectedprivate 范围,但是PHPDoc 不会总是选择文档块来生成文档。

很遗憾,PhpStorm 无法跟踪回调的使用情况。在使用需要回调的方法时,它也不提供参数信息,但至少正式记录了回调。

这种方法还有一个额外的好处,那就是在运行时从原型的reflection 验证回调定义。

【讨论】:

【参考方案3】:

目前在 PhpStorm 中是不可能的。我什至想不出通过其他方式做相对相同的其他解决方案。

【讨论】:

此功能目前正在为即将到来的“官方”PHP-DOC规范here和here进行规划/讨论。

以上是关于如何使用 PHPDoc 对 Callable 的参数进行类型提示?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 解析 phpDoc 样式的注释块?

如何使用带有重载方法的phpDoc?

如何将 PHP 代码块放入 PHPDoc DocBlock

什么是 PHPDoc Eclipse 多类型:以及如何使用它?

phpDoc 类常量文档

如何在 PHPDoc 中弃用 PHP 的魔法属性?