pluck 和 map 均为 Collection 实例方法,不能直接用于原生 PHP 数组,须先用 collect() 包装;pluck 仅提取指定键或嵌套路径的值生成新集合,非过滤或查找;map 用于映射转换并返回新集合,回调必须有返回值。
直接说结论:pluck 和 map 都是 Collection 实例方法,不能用于原生 PHP 数组;必须先用 collect() 包装,否则会报 Call to undefined method 错误。
pluck 只提取指定键(或嵌套路径)
的值,生成新集合,不改变原结构。它不是“过滤”也不是“查找”,更不是“去重”。
$arr = ['name' => 'Tom', 'age' => 25]; collect($arr)->pluck('name') → 返回空集合,因为 pluck 默认按「数组元素」处理,而这里只有一个关联项,不是「含多个子数组的集合」$users->pluck('name', 'id') 是合法的,但写成 $users->pluck('id', 'name') 就会导致键值颠倒,后续用 array_key_exists 查找时失效posts.0.title,却写成 posts.0.title(正确),但若实际是 posts->first()->title,那得用 map + 访问器,pluck 不支持动态调用方法map 是映射转换,返回**新集合**,原集合不变。它不关心数据类型,但你传的回调函数必须有返回值,否则结果全是 null。
$users->map(fn($u) => $u->merge(['email' => strtolower($u->email)]))
map 提取需要的字段:$users->map->only(['id', 'name', 'email'])
map 回调里改原始模型属性(如 $u->name = strtoupper($u->name))是生效的,但这违背函数式原则,且下次再调用 map 时值已变单独用 pluck 只能抽字段,单独用 map 太重。两者组合常用于构造下拉选项、ID 映射表、前端所需扁平结构。
collect($users)
->filter(fn($u) => $u->active)
->map(fn($u) => [
'value' => $u->id,
'label' => "{$u->name} ({$u->email})",
'disabled' => $u->banned,
])
->pluck('label', 'value')
id 为键、格式化字符串为值的集合,适合传给 Vue/React 下拉组件filter,pluck 仍会执行,但可能包含 null 键(当 value 为 null 或 0 时,PHP 会转成空字符串键)pluck('label', 'value') 中第二个参数是「作为键的字段」,不是索引序号,别和 values() 混淆最易被忽略的一点:Collection 方法链式调用中,一旦用了 toArray() 或 jsonSerialize(),后续就不能再调 pluck 或 map —— 它们只属于 Illuminate\Support\Collection 实例,不是数组。调试时用 dd(get_class($var)) 看一眼比猜快得多。