如何指示一个参数;包括特质“;在PHPDoc

如何指示一个参数;包括特质“;在PHPDoc,php,phpstorm,phpdoc,Php,Phpstorm,Phpdoc,最近,我在使用PhpStorm实现PHP应用程序时遇到了一个有趣的情况。下面的代码片段说明了该问题 interface I{ function foo(); } trait T{ /** * @return string */ public function getTraitMsg() { return "I am a trait";

最近,我在使用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
        }
    }
接口I{
函数foo();
}
性状T{
/**
*@返回字符串
*/
公共函数gettraitsg()
{
返回“我是一种特质”;
}
}
A级执行器I{
使用T;
函数foo(){}
}
C类实现I{
使用T;
函数foo(){}
}
B类{
/**
*@param I$input gettraitsg();//Phpstorm在这里异常
}
}

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

AFAIK您不能以这种方式键入提示特征用法(
@param
仅接受标量类型或类/接口+一些)

理想的解决方案是将
gettraitsg()
声明放入
I
接口中

如果不能做到这一点。。然后您可以指定此处只能传递
A
C
的实例(因为它们利用了该特性):

如果此类可能类的名称事先未知(例如,它是一个库代码,最终类可以是每个新项目中的任何内容,甚至可以随时添加到当前项目中)。。然后,我建议使用安全措施,无论如何,您都应该在此类代码中使用安全措施(通过
方法\u exists()
):

为什么要使用安全防护?因为您可以传递另一个类
K
的实例,该类实现
I
,但不使用trait
T
。在这种情况下,没有防护装置的代码将被破坏



只是想澄清一下:您可以使用
@param I | T$input
指定该方法期望实现
I
或使用
T
的实例。。但是它只适用于PhpStorm(不确定其他IDE)——AFAIK它不被实际的PHPDocumentor接受,并且似乎不适合PHPDoc。

AFAIK您不能以这种方式键入提示特性用法(
@param
只接受标量类型或类/接口+一些)

理想的解决方案是将
gettraitsg()
声明放入
I
接口中

如果不能做到这一点。。然后您可以指定此处只能传递
A
C
的实例(因为它们利用了该特性):

如果此类可能类的名称事先未知(例如,它是一个库代码,最终类可以是每个新项目中的任何内容,甚至可以随时添加到当前项目中)。。然后,我建议使用安全措施,无论如何,您都应该在此类代码中使用安全措施(通过
方法\u exists()
):

为什么要使用安全防护?因为您可以传递另一个类
K
的实例,该类实现
I
,但不使用trait
T
。在这种情况下,没有防护装置的代码将被破坏



只是想澄清一下:您可以使用
@param I | T$input
指定该方法期望实现
I
或使用
T
的实例。。但它只适用于PhpStorm(不确定其他IDE)--因为它不被实际的PHPDocumentor接受,并且似乎不适合PHPDoc。

这有点老套,但您可以使用
类使用它返回已使用特征的列表。并在PHPDoc中将
T
作为@param类型添加到autocomplete中

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
        }
    }
}
B类{
/**
*@param I | T$input gettraitsg();//Phpstorm在这里疯狂了
}
}
}

这有点老套,但您可以使用
class\u uses
它返回已使用特征的列表。并在PHPDoc中将
T
作为@param类型添加到autocomplete中

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
        }
    }
}
B类{
/**
*@param I | T$input gettraitsg();//Phpstorm在这里疯狂了
}
}
}
“//Phpstorm在这里疯了”--不,不是。它只是试图向您发出代码不正确的信号

方法
doSomethingCool()
的契约不要求
$input
公开任何名为
gettraitsg()
的方法。docblock说它应该实现接口I
,但docblock不是代码,它只帮助PhpStorm提供验证和建议

由于您没有键入提示参数
$input
,因此代码:

$b = new B();
$b->doSomethingCool(1);
$b = new B();
$b->doSomethingCool(1);
有效,但当它尝试执行行
$msg=$input->gettraitsg()时就会崩溃

如果要在
$input
上调用
gettraitsg()
,必须:

  • 声明
    $input
    的类型
  • 确保声明的
    $input
    类型公开名为
    gettraitsg()
    的方法
对于第一步,您现有的
B类代码应为:

class B {
    /**
     * @param I $input 
     */
    public function doSomethingCool(I $input) {
       $msg = $input -> getTraitMsg();
    }
}
请在参数列表中的参数
$input
前面注明类型
I

完成下一步的最简单方法是将方法
gettraitsg()
声明到
接口I

interface I {
    function foo();
    function getTraitMsg();
}
现在,代码:

$b = new B();
$b->doSomethingCool(1);
$b = new B();
$b->doSomethingCool(1);
当异常到达行
$b->doSomethingTool(1)时引发异常(即在进入功能之前)。这是PHP告诉您该方法没有使用正确的参数调用的方式。无论是
A
还是
C
类型,都必须向其传递一个实现
接口I
的对象。它可以是实现接口I的任何其他类型,没有人关心它是否使用trait T来实现它。

“//Phpstorm在这里崩溃了”--不,它不是。它只是试图向您发出代码不正确的信号

方法
doSomethingCool()
的契约不要求
$input
公开任何名为
gettraitsg()
的方法。docblock说的没错