如何表示"包含特征"在PHPDoc中

时间:2016-02-24 05:25:26

标签: php phpstorm phpdoc

最近,当使用PhpStorm实现PHP应用程序时,我遇到了一个有趣的情况。以下代码段说明了此问题。

    interface I{
        function foo();
    }

    trait T{
        /**
         * @return string
         */
        public function getTraitMsg()
        {
            return "I am a trait";
        }
    }

    class A implements I{
        use T;
        function foo(){}
    }

    class C implements I{
        use T;
        function foo(){}
    }

    class B {
        /**
         * @param I $input <===Is there anyway to specify that $input use T? 
         */
        public function doSomethingCool($input){ //An instance of "A" or "C"
           $msg = $input -> getTraitMsg();  //Phpstorm freaks out here
        }
    }

我的问题在评论中。如何指示$input参数实现I并使用T

3 个答案:

答案 0 :(得分:4)

它有点乱,但你可以使用class_uses它返回使用过的特征列表。并在PHPDoc中将T添加为@param类型以用于自动完成

class B {
    /**
     * @param I|T $input <===Is there anyway to specify that $input use T?
     */
    public function doSomethingCool($input){ //An instance of "A" or "C"
        $uses = class_uses(get_class($input));
        if (!empty($uses['T'])) {
            echo $input->getTraitMsg();  //Phpstorm freaks out here
        }
    }
}

答案 1 :(得分:2)

AFAIK你不能以这种方式输入暗示特征用法(@param只接受标量类型或类/接口+一些keywords)。

您的理想解决方案会将getTraitMsg()声明放入I界面。

如果无法做到这一点..那么您可以指定只能传递AC的实例(因为它们使用该特征):

/**
 * @param A|C $input
 */
public function doSomethingCool($input)
{
    $msg = $input->getTraitMsg();  // PhpStorm is good now
}

如果事先知道这些可能类别的名称(例如,它的库代码和最终类可以是每个新项目中的任何内容,甚至可以随时添加到当前项目中)..那么我建议使用安全措施,无论如何都应该使用此类代码(通过method_exists()):

/**
 * @param I $input
 */
public function doSomethingCool($input)
{
    if (method_exists($input, 'getTraitMsg')) {
        $msg = $input->getTraitMsg();  // PhpStorm is good now
    }
}

为什么要使用保障措施?因为您可以传递实现K但不使用特征I的另一个类T的实例。在这种情况下,没有后卫的代码就会中断。

只是为了澄清:您可以使用@param I|T $input指定该方法需要实现I的实例或使用T ..但它只适用于PhpStorm(不确定)关于其他IDE) - AFAIK它不被实际的PHPDocumentor接受,似乎不适合PHPDoc proposed standard

答案 2 :(得分:0)

&#34; // Phpstorm在这里吓坏了#34; - 不,它不是。它只是试图告诉你你的代码不正确。

方法doSomethingCool()的合同并不要求$input公开任何名为getTraitMsg()的方法。 docblock表示它应该实现interface I,但docblock不是代码,它只会帮助PhpStorm帮助您进行验证和建议。

因为您没有键入 - 提示参数$input,所以代码:

$b = new B();
$b->doSomethingCool(1);

有效但尝试执行第$msg = $input -> getTraitMsg();行时会崩溃。

如果您想在getTraitMsg()上致电$input,则必须:

  • 声明$input;
  • 的类型
  • 确保声明的$input类型公开了一个名为getTraitMsg()的方法。

第一步,您现有的班级B代码应为:

class B {
    /**
     * @param I $input 
     */
    public function doSomethingCool(I $input) {
       $msg = $input -> getTraitMsg();
    }
}

请在参数列表中注明参数I前面的$input类型。

完成下一步的最简单方法是将方法getTraitMsg()声明为interface I

interface I {
    function foo();
    function getTraitMsg();
}

现在,代码:

$b = new B();
$b->doSomethingCool(1);

在到达行$b->doSomethingCool(1);时(即在进入函数之前)抛出异常。这是PHP的方法告诉你没有使用正确的参数调用该方法。您必须传递一个实现interface I的对象,无论它是A还是C。它可以是实现interface I的任何其他类型,如果它使用trait T来实现它,则无人问津。