本页目标
本页的目标不是介绍collect() 的用法,而是为阅读 Laravel 本体的实现代码提供一份地图。
面向的读者:已经熟悉 Collection 方法列表,接下来想理解「为什么会这样设计」的人。
历史变迁
Collection 的结构在引入LazyCollection 时进行了大规模整理。
Laravel 5.8 之前
Illuminate\Support\CollectionIlluminate\Database\Eloquent\Collection(继承Collection)
LazyCollection、Enumerable、EnumeratesValues。
Laravel 6.0 的变化
配合新增的LazyCollection,将公共 API 拆分到 Enumerable(接口)与 EnumeratesValues(trait)中。
当前整体结构(Laravel 13)
参考:laravel/framework v13.x
实际文件路径是
src/Illuminate/Collections/*,但命名空间仍保持为 Illuminate\Support。阅读代码时请分别确认「路径」和「namespace」。PHPDoc 与 PHPStan 风格的 Generics
PHP 本身没有 Generics。 但在 Collection 周边,通过 PHPDoc 表达了强类型信息。 主要目的有两个:- 让 IDE 补全更准确
- 提升 PHPStan / Larastan 等静态分析的精度
常见写法
| 写法 | 含义 |
|---|---|
@template TKey of array-key | 将 Key 类型约束为 int|string |
@template-covariant TValue | 将 Value 类型作为协变处理(更容易安全地替换为更具体的类型) |
@implements ...<TKey, TValue> | 向实现的接口传递类型参数 |
@extends ...<TKey, TModel> | 声明继承父类时的类型参数 |
@use ...<TKey, TValue> | 声明使用 trait 时的类型参数 |
在 Eloquent Collection 中的呈现
TValue 具体化为 TModel,map()、filter() 等方法的类型推断会向 Eloquent 模型倾斜,从而得到更强的类型提示。
阅读实现代码的顺序
1. 从入口 Enumerable 开始读
先掌握「提供了什么契约」。
在这里把握方法列表后,后续阅读实现会更快。
2. 在 EnumeratesValues 中追踪公共方法
map、filter、reduce 等大部分公共逻辑都在这里。
之后只看 Collection 与 LazyCollection 的差异部分,可减少无谓的通读。
3. 查看 Collection 与 LazyCollection 的差异
Collection:持有数组并立即求值LazyCollection:使用Generator进行惰性求值
4. 最后阅读 Eloquent\Collection
聚焦 find、load、modelKeys 等针对模型集合的扩展。
理解基础的 Collection 后再看,更容易看清其意图。