PHP - 欺骗返回类型协方差以进行代码预测

问题描述 投票:0回答:1

考虑:

abstract class BaseModel {
    protected static string $dataObjectClass;

    public function toDataObject(): ?IDataObject
    {
        return static::$dataObjectClass::from($this);
    }
}

class FooModel extends BaseModel {
    protected static string $dataObjectClass = FooDataObject::class;
}

$do = (new FooModel)->toDataObject();

$do
上的 PHPStorm 之类的 IDE 中的代码预测将指示
null|IDataObject
的返回类型,并且...不会告诉我有关其作为
FooDataObject
实例的性质的任何有价值信息,除了 IDataObject 中定义的
可能

但是,作为程序员,我可以确定地知道返回的对象要么为 null,要么是

FooDataObject
的实例。

是否有任何技巧可以通知 IDE 返回的类型可以是

FooDataObject

我尝试过的两个半生不熟的解决方案是:

  1. 在子类中重写
    toDataObject()
    ,并将返回类型扩展为
    null|IDataObject|FooDataObject
    。这可以解锁
    FooDataObject
    的属性和方法来进行预测,但这意味着为了一个唯一、愚蠢的目的而重载一个方法——丑陋的开销。
  2. 在 phpdoc 子类中包含
    @method FooDataObject toDataObject()
    。这更加精简和干净,但是,当然,
    @method
    表示法似乎对多种返回类型的支持为零。尝试执行
    @method null|FooDataObject toDataObject()
    ,PHPStorm(至少)只能识别第一种类型。

因此任何提示或技巧将不胜感激。我是代码预测的坚持者,我想在这个应用程序中建立一种实践,使明天的编码变得更容易。

php covariance return-type phpdoc
1个回答
0
投票

当我使用以下内容测试

@method
时,我确实从 PhpStorm 获得了自动完成:

interface I{}
class Data implements I{}

abstract class P
{
    public function getThing(): ?I
    {
        return null;
    }
}


/**
 * @method Data getThing()
 */
class C extends P {}

(new C)->getThing();

正如您所提到的,仅重写该方法以更改返回类型确实会增加冗余,但您还可以进行运行时类型检查,这可能对您有利,也可能没有,特别是因为您可以显式地从返回中删除 null 的可能性。

interface I{}
class Data implements I{}

abstract class P
{
    public function getThing(): ?I
    {
        return null;
    }
}

class C extends P {
    public function getThing(): Data
    {
        return new Data;
    }
}

var_dump((new C)->getThing());

演示:https://3v4l.org/hdscV

编辑抱歉,我忘记了联合类型部分,但这也对我有用:

interface I{}
class Data implements I{}

abstract class P
{
    public function getThing(): null|I
    {
        return null;
    }
}

/**
 * @method null|P getThing()
 */
class C extends P {
}

© www.soinside.com 2019 - 2024. All rights reserved.