each无法修改原集合,因其闭包参数$item是值拷贝而非引用;应改用transform(原地修改)或map+values(生成新集合),each仅适用于日志、发短信等无返回值副作用操作。

不能直接用 each 修改原集合中的元素值,它只提供只读遍历。 想边遍历边改原数据,得换方法或手动索引操作。
为什么 each 无法修改原集合
each 是 Collection 的高阶遍历方法,内部使用 foreach ($this->items as $key => $item),传入闭包的 $item 是值拷贝(PHP 中数组元素默认按值传递),对它赋值不会影响 $this->items 原数组。
常见错误现象:
- 在 each 闭包里写 $item['status'] = 1,执行完后 dump($collection) 发现没变
- 误以为和 JavaScript 的 forEach 行为一致,实际 PHP 数组语义不同
真正能修改原数据的两种方式
推荐根据场景二选一:
- 用
transform:适合批量更新字段,会原地修改$this->items,返回当前实例(链式友好)$collection->transform(function ($item) { $item['price'] = round($item['price'] * 1.1, 2); return $item; // 必须 return,否则变 null }); - 用
map+values:适合需要构造新结构、同时保留键名逻辑较复杂时,但注意它不修改原集合,需重新赋值$collection = $collection->map(function ($item) { $item['updated_at'] = date('Y-m-d H:i:s'); return $item; })->values(); // 重置数字索引(可选)
each 的正确使用场景和替代建议
each 本质是「副作用驱动」的遍历,只适合做日志、发请求、触发事件等不依赖返回值的操作:
- 发送短信:
$collection->each(function ($user) { send_sms($user['phone']); }); - 写日志:
$collection->each(function ($order) { \think\Log::info("process order {$order['id']}"); }); - 如果顺手想改点东西,立刻停 —— 改用
transform或显式索引循环 - 极端情况需用索引改:用
foreach ($collection as $key => &$item)(注意加&引用),但破坏了 Collection 封装性,不推荐
最易被忽略的一点:ThinkPHP 6.x 的 Collection 已移除 each 方法(由 forEach 替代),且 transform 是唯一保证原地修改的内置方法。低版本留下的习惯,在升级后会静默失效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











