【问题标题】:Simulate a generic class in PHP在 PHP 中模拟一个泛型类
【发布时间】:2019-08-25 03:40:48
【问题描述】:

我正在尝试实现一个处理查询的结果类。所以,简单地说,你会有这样的功能:

function all();
function first();
function paginate(int $perPage, int $pageNo = 1);

这很好用,问题是当在多个不同的查询类中使用相同的结果类时,IDE 无法知道返回类型。示例:

UserQuery->results()->all() 将返回一个用户实体数组。

UserQuery->results()->first() 将返回单个用户实体。

在某些语言中,您有泛型,这意味着我可以在 UserQuery 类中使​​用 Results<User>,然后我的 Results 类可以分别返回 T[]T

我的一个想法是将一个空实体作为构造函数传递给 Results 类,然后尝试使用该属性作为返回类型,但我想不通。有什么解决方法吗?我要解决的主要问题是 IDE 自动完成和分析,因此纯 phpDoc 解决方案非常适合我的用例。

我能想到的唯一其他解决方法是必须为每种实体类型编写一个单独的 Results 类,这会很累。

【问题讨论】:

  • 在 Eclipse 和 PHP Storm 中,您可以手动执行类似 /* @var $foo Users */ 的类型提示,例如在循环之前,以便 as $foo 部分具有自动完成功能。
  • 是的,当 IDE 没有检测到正确的类型时,我通常会这样做。不幸的是,最终编写的代码几乎与最后一个选项一样多,因为我必须记录每次使用的返回值,而不仅仅是定义它的位置。它对重构也不是很友好。

标签: php generics phpdoc


【解决方案1】:

我认为没有办法完全按照您的描述进行操作,但在类似情况下,我建议为每个结果类型使用代理类,并使用 phpDocumentor 的@method 记录正确的返回类型。该解决方案具有附加价值,可以为任何特定类型的结果修改和扩展提供一个很好的位置。这是一个例子:

abstract class Results
{
    function all(): array
    {
    }

    function first()
    {
    }

    function paginate(int $perPage, int $pageNo = 1): array
    {
    }
}

class User { }

/**
 * @method User[] all()
 * @method User first()
 * @method User[] paginate(int $perPage, int $pageNo = 1)
 */
class UserResults extends Results { }

class UserQuery
{
    /**
     * @var UserResults
     */
    private $results;

    public function __construct()
    {
        $this->results = new UserResults();
    }

    public function results(): UserResults
    {
        return $this->results;
    }
}

$userQuery = new UserQuery();
$test = $userQuery->results()->all();

【讨论】:

  • 直到现在我才注意到您关于“每个实体类型的单独结果类,将被证明是令人筋疲力尽”的评论,但恕我直言,在提议的形式中,这些结果实现类可以很容易地自动生成,并且不会花费任何额外费用工作。
  • 是的,问题是当抽象类发生变化或引入新方法时,我必须在大约 30 个子类上重新编写 PHPDoc,不过谢谢你把这些放在一起,我'确信它可以帮助其他可能遇到它的人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
  • 2010-12-01
相关资源
最近更新 更多