PHP 抽象方法的类型提示实现 - 存储库模式

PHP Type Hinting Implementation of Abstract Method - Repository Pattern

问题

是否可以使用 model/repository 模式在 PhpStorm 中完成行代码?

我的设置

我正在使用 Laravel 并实现存储库模式,如 Laracasts 视频中所述。

代码

这是一个基本示例,说明模型如何在内部工作 Laravel 以及如何获得模型属性的代码完成似乎是不可能的。

此代码正常工作并打印出 'billy',但是属性 $name 没有类型提示,不会在 PhpStorm 中完成代码。类型提示优先于父属性定义类型而不是子属性,这对我来说很奇怪。

<?php

// Models
abstract class Model {
    public $sqlTableName;

    public function findFromDatabase($id)
    {
        $model = new $this;

        // This would be grabbed using table name and $id
        $fakeDatabaseRow = ['name' => 'billy', 'job' => 'engineer'];

        foreach ($fakeDatabaseRow as $column => $value) {
            $model->$column = $value;
        }

        return $model;
    }
}

class User extends Model {
    public $name;
    public $job;

    public $sqlTableName = 'users';
}

// Repositories
abstract class RepositoryBase {
    /**
     * @var Model
     */
    public $model;

    public function find($id)
    {
        $this->model = $this->model->findFromDatabase(1);

        return $this->model;
    }
}

class UserRepository extends RepositoryBase {
    /**
     * @var User
     */
    public $model;

    public function __construct(User $model)
    {
        $this->model = $model;
    }
}

// Run
$model = new User();

$userRepository = new UserRepository($model);

echo $userRepository->find(1)->name;

一个丑陋的修复程序

唯一真正获得代码完成的方法似乎是用新的 php 文档块重新定义子函数:

class UserRepository extends RepositoryBase {
    /**
     * @var User
     */
    public $model;

    public function __construct(User $model)
    {
        $this->model = $model;
    }

    // I need to replace this function for every different repository
    // even though they are all the same
    /**
     * @param $id
     * @return User
     */
    public function find($id)
    {
        return parent::find($id);
    }
}

但是我有数百个模型、存储库和存储库函数。重写每个实现中的所有函数将是一项艰巨的工作。

有没有办法让 PhpStorm 使用子类的类型提示声明而不是父类而不需要重新声明方法?

您可以使用 abstract 关键字来卸载方法的实现。

abstract class Model {
    abstract public function find($id);
}

强制任何扩展模型的对象实现该功能。

我希望这是有道理的。

在我最初发布这个问题的上下文中,我无法找到一个解决方案来获得模型和存储库的正确类型提示。


妥协方案

在进一步研究存储库和 mvc php 模式后,我得出结论,要使用更具体和详细的​​存储库功能。


错误的方式

例如,我在 controllers/logic 类 中使用 存储库基本函数 ,如下所示:

$users =
    $userRepository->where('created_at', '<', '2016-01-18 19:21:20')->where(
            'permission_level',
            'admin'
        )->orderBy('created_at')->get('id');

$posts =
    $postRepository->where('posted_on', '<', '2016-01-18 19:21:20')
        ->where('content', '!=', 'null')
        ->chunk(
            function ($posts) {
                // do things
            }
        );

正确的方法

现在我在特定的存储库中为我的所有需求编写单独的数据库逻辑函数,所以我的核心classes/controllers最终看起来像这样:

$users = $userRepository->getAdminIdsCreatedBeforeDate('2016-01-18 19:21:20');
$posts = $postRepository->chunkFilledPostsBeforeDate('2016-01-18 19:21:20', function() {});

这样所有数据库逻辑都被移动到特定的存储库,我可以键入提示它返回的模型。这种方法还可以使代码更清晰、更易于阅读,并进一步将您的核心逻辑与 Eloquent.

分开