PHP中的泛型:为什么需要以及如何使用

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP 中的泛型:为什么需要以及如何使用



泛型是 PHP 世界中最受期待和讨论最多的特性之一。尽管截至 PHP 8.x,它们尚未在语言中完全实现,但社区已经积极使用替代方法并等待完整支持。在本文中,我们将分析 PHP 中为什么需要泛型、如何模拟它们以及它们为开发者带来的优势。



什么是泛型,为什么需要它们?



泛型允许你创建能够处理不同数据类型但保持严格类型检查的类、接口和函数。在静态类型语言(Java、C#、TypeScript)中,它们早已成为标准。对于最初是动态类型的 PHP 来说,泛型是朝着更可靠、更易读代码迈出的一步。



泛型解决的主要问题:

  • 类型安全 — 消除因传递错误类型数据而导致的错误。
  • 减少代码重复 — 无需为每种类型编写单独的类。
  • 提升可读性 — 能清晰看出函数或类处理哪些类型。
  • IDE 支持 — 自动补全和代码分析更加精确。


没有泛型的问题:PHP 示例



想象一下,你需要创建一个只存储整数的集合。如果没有泛型,你可能会这样写:



class IntegerCollection {    private array $items = [];

public function add(int $item): void { $this->items[] = $item; }

public function get(int $index): int { return $this->items[$index]; }}


这样可行,但如果你需要一个字符串集合,就得复制代码并更改类型。如果你需要一个对象集合,也是如此。这会导致代码重复和体积增加。



使用注释和 PHPDoc 在 PHP 中模拟泛型



目前,PHP 在语法层面不支持完整的泛型,但可以通过 PHPDoc 注释 和专用库(例如 phpstan/phpstan 或 vimeo/psalm)来模拟它们。



带有注释的泛型类示例:



/** * @template T */class Collection {    private array $items = [];

/** * @param T $item */ public function add($item): void { $this->items[] = $item; }

/** * @return T */ public function get(int $index) { return $this->items[$index]; }}


现在,在使用类时,可以指定具体类型:



/** @var Collection<int> $intCollection */$intCollection = new Collection();$intCollection->add(42);$value = $intCollection->get(0); // IDE 知道这是 int 类型


静态分析工具(PHPStan、Psalm)会检查你是否没有向整数集合中传入字符串。这提供了与完整泛型几乎相同的安全性。



PHP 中泛型的实际应用示例



让我们看几个泛型特别实用的场景。



1. Doctrine 中的 Repository



在 Doctrine ORM 中,你经常使用 Repository。泛型有助于明确指定 Repository 处理哪个实体:



/** * @template T of object */interface RepositoryInterface {    /**     * @param int $id     * @return T|null     */    public function find(int $id): ?object;}

/** * @implements RepositoryInterface<User> */class UserRepository implements RepositoryInterface { public function find(int $id): ?User { // 查找逻辑 }}


2. 带泛型的策略模式



泛型允许你创建

博客

书籍推荐