如何在 PHPDoc 中指示 "include trait" 的参数
How to indicate a parameter that "include trait" in 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
?
AFAIK 你不能以这种方式键入提示特征用法(@param
只接受标量类型或 classes/interfaces + 一些 keywords)。
理想的解决方案 是将 getTraitMsg()
声明放入 I
接口。
如果这不能完成..那么你可以指定只有 A
或 C
的实例可以在这里传递(因为它们利用了那个特征):
/**
* @param A|C $input
*/
public function doSomethingCool($input)
{
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
如果事先不知道这些可能的 classes 的名称(例如,它是一个库代码,最终 classes 可以是每个新项目中的任何东西,甚至可以随时添加到当前项目中) .. 然后我建议 使用安全措施 ,无论如何你都应该使用这样的代码(通过 method_exists()
):
/**
* @param I $input
*/
public function doSomethingCool($input)
{
if (method_exists($input, 'getTraitMsg')) {
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
}
为什么要使用保障?因为您可能会传递另一个实现 I
但不使用特征 T
的 class K
的实例。在这种情况下,没有守卫的代码将被破坏。
澄清一下:您可以使用 @param I|T $input
来指定该方法期望实例实现 I
或使用 T
.. 但它仅适用于 PhpStorm(不确定其他IDEs) -- AFAIK 它不被实际的 PHPDocumentor 接受并且似乎不适合 PHPDoc proposed standard.
它有点笨拙,但您可以使用 class_uses
它 returns 已用特征列表。并在 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
}
}
}
"//Phpstorm 在这里吓坏了" -- 不,不是。它只是试图向您发出信号,表明您的代码不正确。
方法 doSomethingCool()
的契约不要求 $input
公开任何名为 getTraitMsg()
的方法。 docblock 说它应该实现 interface I
但 docblock 不是代码,它只帮助 PhpStorm 帮助您进行验证和建议。
因为您没有对参数 $input
进行类型提示,代码:
$b = new B();
$b->doSomethingCool(1);
是有效的,但它在尝试执行行 $msg = $input -> getTraitMsg();
.
时立即崩溃
如果您想在 $input
上致电 getTraitMsg()
,您必须:
- 声明
$input
的类型;
- 确保
$input
的声明类型公开了一个名为 getTraitMsg()
. 的方法
对于第一步,您现有的 class B
代码应为:
class B {
/**
* @param I $input
*/
public function doSomethingCool(I $input) {
$msg = $input -> getTraitMsg();
}
}
请在参数列表中的参数$input
前备注类型I
。
完成下一步的最简单方法是将方法 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
来实现它。
最近我 运行 在使用 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
?
AFAIK 你不能以这种方式键入提示特征用法(@param
只接受标量类型或 classes/interfaces + 一些 keywords)。
理想的解决方案 是将 getTraitMsg()
声明放入 I
接口。
如果这不能完成..那么你可以指定只有 A
或 C
的实例可以在这里传递(因为它们利用了那个特征):
/**
* @param A|C $input
*/
public function doSomethingCool($input)
{
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
如果事先不知道这些可能的 classes 的名称(例如,它是一个库代码,最终 classes 可以是每个新项目中的任何东西,甚至可以随时添加到当前项目中) .. 然后我建议 使用安全措施 ,无论如何你都应该使用这样的代码(通过 method_exists()
):
/**
* @param I $input
*/
public function doSomethingCool($input)
{
if (method_exists($input, 'getTraitMsg')) {
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
}
为什么要使用保障?因为您可能会传递另一个实现 I
但不使用特征 T
的 class K
的实例。在这种情况下,没有守卫的代码将被破坏。
澄清一下:您可以使用 @param I|T $input
来指定该方法期望实例实现 I
或使用 T
.. 但它仅适用于 PhpStorm(不确定其他IDEs) -- AFAIK 它不被实际的 PHPDocumentor 接受并且似乎不适合 PHPDoc proposed standard.
它有点笨拙,但您可以使用 class_uses
它 returns 已用特征列表。并在 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
}
}
}
"//Phpstorm 在这里吓坏了" -- 不,不是。它只是试图向您发出信号,表明您的代码不正确。
方法 doSomethingCool()
的契约不要求 $input
公开任何名为 getTraitMsg()
的方法。 docblock 说它应该实现 interface I
但 docblock 不是代码,它只帮助 PhpStorm 帮助您进行验证和建议。
因为您没有对参数 $input
进行类型提示,代码:
$b = new B();
$b->doSomethingCool(1);
是有效的,但它在尝试执行行 $msg = $input -> getTraitMsg();
.
如果您想在 $input
上致电 getTraitMsg()
,您必须:
- 声明
$input
的类型; - 确保
$input
的声明类型公开了一个名为getTraitMsg()
. 的方法
对于第一步,您现有的 class B
代码应为:
class B {
/**
* @param I $input
*/
public function doSomethingCool(I $input) {
$msg = $input -> getTraitMsg();
}
}
请在参数列表中的参数$input
前备注类型I
。
完成下一步的最简单方法是将方法 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
来实现它。