编程

Laravel Eloquent 中使用泛型

74 2024-10-20 02:04:00

编程中的泛型是一种特性,允许你使用占位符类型定义函数、类和数据结构。使你能够编写更灵活和可重用的代码。

泛型通常用于 Java、C# 和 C++ 等静态类型语言。Python 等动态语言也支持它。

为什么使用泛型?

使用泛型由多个好处:

  • 类型安全:泛型确保关联返回正确类型的模型,从而降低了由于模型类型不正确而导致的运行时错误的风险。
  • 更好的 IDE 支持:使用泛型时,IDE 可以提供更好的自动补全和类型检查,使开发更容易,并降低出错的可能性。
  • 改善可读性:泛型的使用使代码更加自文档化。从方法签名中可以清楚地看出涉及什么类型的关系和模型。

以下是 Java 中典型的泛型的样子:

public <T> T getFirstElement(List<T> list) {
    return list.get(0);
}

本例中,getFirstElement 函数接受 T 类型的 List 并返回 T 类型的元素。T 是一个占位符类型,在调用函数时可以用任何其他类型替换。

在 Laravel 中使用泛型

说到PHP,泛型似乎仍然是一个遥不可及的梦想,但这并没有阻止我们使用它们,这要归功于 PHPStan 或 PSalm 等工具,它们可以让你在 PHP 代码中添加静态类型检查。

我们可以将泛型定义为注释或注解,为 IDE 提供类型提示,PHPStan 等工具可以使用它们进行静态分析。

在最近的 Laravel 版本中,一个社区成员添加了在 Eloquent 模型中使用泛型的支持。泛型在这里的作用是增加指定类或方法将使用的类型的能力。

泛型提供了一种类型提示机制和更好的代码可读性,特别是在处理 Eloquent 模型中的关联时。
参考下例。

class User extends Model
{
    /** @return HasOne<Address, $this> */
    public function address(): HasOne
    {
        return $this->hasOne(Address::class);
    }

    /** @return HasMany<Post, $this> */
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}

解析

如你所见,我们现在可以指定关联的返回类型,但除此之外,我们还可以指定关联所关联的模型的类型。

  • HasOne<Address,$this>:这表示 address 方法返回一个 HasOne 关联,其中相关模型是 Address,父模型是当前  User 实例。
  • HasMany<Post,$this>:这表示 posts 方法返回一个 HasMany 关联,其中相关模型是 Post,父模型是当前 User 实例。

其他方法也是如此,如 belongsTohasManyThroughbelongsToMany 等。

现在,如果定义的类型存在不一致,比如 Larastan(Laravel 的 PHPStan 包装器)将抛出一条详细的错误消息,指出问题所在。

以下面为例。

/** @return HasMany<Comment, $this> */
public function posts(): HasMany
{
    return $this->hasMany(Post::class);
}

本例中,posts 方法指定了一个泛型 HasMany<Comment, $this>,却返回一个 Post::class 关联。

运行 Larastan (使用命令 ./vendor/bin/phpstan analyse) 将会生成如下错误信息。

  Line   app/Models/User.php
 ------ ----------------------------------------------------------------------------
  10     Method App\Models\User::posts() should return 
         App\Models\Relations\HasMany<App\Models\Comment, App\Models\User> 
         but returns App\Models\Relations\HasMany<App\Models\Post, App\Models\User>.
 ------ ----------------------------------------------------------------------------

 [ERROR] Found 1 error

这就是泛型如何帮助我们在 Laravel 中编写更健壮和可维护的代码,并使我们避免丑陋的运行时错误。