Collection是Laravel具备链式调用、惰性求值与不可变语义的核心对象,非数组封装;应使用first()/last()而非下标访问,filter/where/reject各司其职,map()返回新实例而transform()修改原集合,chunk/splice/partition适用不同切片场景。

Collection 是 Laravel 的核心工具,不是语法糖,别当数组用
Collection 不是 PHP 数组的简单封装,而是一个具备链式调用、惰性求值(部分方法)、不可变语义(多数方法返回新实例)的对象。直接用 foreach 遍历或用 [] 下标访问虽能工作,但会丢失过滤、映射、分页等关键能力,也容易在嵌套操作中引发意外的引用问题。
常见错误现象:
– 用 $collection[0] 取首项,结果报错(Collection 不支持数组下标访问)
– 链式调用中途赋值给变量,后续修改原变量却误以为影响了前面的链路(实际每步都返回新实例)
– 在循环中反复调用 push() 构建集合,性能差且违背函数式习惯
- 取首项用
first(),末项用last(),不支持$col[0] - 需要“就地修改”时,明确用
transform()或mapInto()等可变方法(少数) - 构建集合优先用
collect($array)一次性初始化,避免循环中push()
filter() / where() / reject() 这三个最常混用的方法怎么选
filter() 接回调函数,做任意逻辑判断;where() 是快捷键,只适合简单字段匹配(支持点号路径、== 语义、支持 null 安全比较);reject() 是 filter() 的反向——别用 filter(fn => !condition) 替代 reject(),语义不清且少一层优化。
collect([
['name' => 'Alice', 'active' => true, 'score' => 85],
['name' => 'Bob', 'active' => false, 'score' => 92],
['name' => 'Cara', 'active' => true, 'score' => null],
])
->where('active', true) // ✅ 简单布尔匹配
->where('score', '>=', 90) // ✅ 支持操作符
->where('name.0', 'A') // ✅ 支持点号取嵌套字符串首字符
->reject(fn ($u) => $u['score'] === null); // ✅ 明确排除空分注意:where('score', null) 会同时匹配 null 和 0(松散比较),要严格判空请用 whereNull('score') 或 reject() + 闭包。
map() vs transform():什么时候该改原集合,什么时候该生成新集合
map() 返回全新 Collection,原集合不变;transform() 直接修改当前实例(返回 $this),适用于需复用同一变量名、且后续不再需要原始数据的场景。Laravel 官方文档强调“Collection 默认不可变”,所以 transform() 是显式打破约定的操作,应有明确理由。
- 处理响应数据、构造 API 输出:用
map()—— 保持输入干净,便于调试和复用 - 批量更新模型属性后立即用于保存:可用
transform(),避免多一次实例化开销 -
map()内部不支持修改原数组键名;如需重键,用mapWithKeys() -
transform()对空集合无效(不报错但无效果),而map()总是返回新实例
chunk() / splice() / partition() 这些“切片类”方法的真实适用边界
它们解决的是不同维度的拆分需求:chunk() 按数量均分(适合分批处理队列任务);splice() 类似数组的 array_splice(),支持删除+插入+偏移(适合 UI 层动态插入广告位);partition() 是二元分类(如把用户分成“已验证”和“未验证”两组),返回含两个子集的数组,不是 Collection。
$users = collect([/* ... */]);
// 分批发邮件,每 50 人一批
$users->chunk(50)->each(function ($batch) {
Mail::to($batch)->send(new WelcomeBatch());
});
// 在第 3 个位置插入一个推荐用户
$users->splice(3, 0, [new User(['name' => 'Sponsored'])]);
// 一分为二,得到 [verified, unverified]
[$verified, $unverified] = $users->partition('email_verified_at'); // 注意:返回的是 array,不是 Collection
容易被忽略的点:partition() 返回的是 PHP 数组,不是 Collection 实例,如果后续还要链式操作,得再包一层 collect();splice() 的第二个参数是“删除数量”,传 0 才是纯插入,这点和 JS 的 splice() 一致,但常被 PHP 开发者误写成 1。










