从构建器方法调用的类型提示方法

Posted

技术标签:

【中文标题】从构建器方法调用的类型提示方法【英文标题】:Type hinting methods called from builder method 【发布时间】:2017-10-23 02:50:05 【问题描述】:

考虑一个使用静态构建器返回模型实例的 Active Record 实现。这是要演示的 ModelBuilder 和 Model 类的非常简化版本,所有与问题无关的代码都已删除:

class ModelBuilder 
    public function __construct($class) 
        $this->class = $class
    

    private function _execute() 
        $result = $pdo->query("SELECT * FROM $this->class");
        return $result->fetchAll(PDO::FETCH_CLASS, $this->class);
    

    public function all() 
        return $this->_execute();
    

    public function one() 
        return $this->_execute()[0];
    


class Model 
    public static function builder() 
        return new ModelBuilder(get_called_class());
    


class FooModel extends Model 


为了得到一个 Foo 项目,我们这样调用 FooModel 类:

$foo = FooModel::builder()->one();

在这种情况下,智能 IDE(在我的情况下为 phpStorm)不知道 $foo 是什么类型的对象。我可以在每次创建对象时对变量 /** @var $foo FooModel */ 进行类型提示,但我更喜欢在 all()one() 方法上进行适当的类型提示。

添加到all()one() 方法的正确类型提示是什么? 请注意,static 不起作用,我相信因为 ModelBuilder 不是初始调用的祖先类,它在builder() 方法中被显式调用。

这个特定项目使用的是 PHP 5.6,但也欢迎使用 PHP 7 特定的答案。

【问题讨论】:

你不能。添加该表扬是唯一可行的选择。当然,我也建议不要使用活动记录反模式,但这只是我对 OOP 和 SRP 的愚蠢想法。 @tereško:我很高兴听到你反对 ActiveRecord 模式的论点,因为我经常使用它。我想学习更好的方法。 使用更好的持久化模式称为“data mapper”,但也有“表数据网关”之类的东西(有些人习惯将其描述为“存储库”,尽管这并不是说)。避免 AR 的主要原因是性能。 【参考方案1】:

如果您的模型具有像 BaseModel 这样的父类 - 您可以在文档块内的返回块中使用 BaseModel allone 方法,例如:

/**
* @return BaseModel Model instance.
*/
public function one() 
    return $this->_execute()[0];

但在这种情况下 - 它只是 BaseModel 它不是 FooModel 也不是 BooModel... 您将只能访问 BaseModel 方法和属性,但不能访问特定于 FooModel...

为了拥有特定模型 - 您已经使用适当的文档块覆盖子模型中所需的方法,例如:

class FooModel extends BaseModel

    /**
    * @return FooModel Foo model instance.
    */
    public function one() 
        return parent::one();
    

或者有类的文档块,像这样:

/**
 * @method FooModel one Foo model instance.
 */
class FooModel extends BaseModel


或者像你已经提到的那样使用 doc-block /** @var $foo FooModel */

【讨论】:

谢谢。事实上,我正在寻找一种让FooModel 属性可用的方法,而不仅仅是Model 的属性,并且我想避免仅仅为了类型提示而重写每个扩展类中的方法。我想它要么是覆盖,要么我必须坚持使用文档块。 我已经更新了我的答案,添加了示例 @method FooModel one Foo model instance. 您可以为 FooModel 类设置此块,因此您不必覆盖 one 方法。 感谢您的更新,我不知道课堂上的@method 类型提示。好的!但是,它在这里不起作用,因为one()ModelBuilder 类的方法,而不是Model

以上是关于从构建器方法调用的类型提示方法的主要内容,如果未能解决你的问题,请参考以下文章

C++ 从函数调用的多次返回中构建字符串向量的最佳方法

如何使用 C++ 模板实现从类型到对象方法调用的映射?

在基类中创建的对象调用方法中的 PHP 类型提示

在 iOS 中调用 Google Toolbox for Mac NSString 类别方法时无法识别的选择器

Flutter:从 appbar 调用 listview builder 中的方法

Flutter:当我抛出异常时,构建器在未来的构建器中调用了两次