ThinkPHP 的 Collection::flatten() 默认仅浅层扁平化,只展开第一层嵌套;如需深度扁平化,须手动实现递归逻辑,推荐使用 array_reduce + 递归闭包或 map 配合递归匿名函数。

Collection::flatten() 在 ThinkPHP 中确实能将多维数组转为一维,但它**默认只展开一层嵌套**,不是深度递归扁平化——这点不注意,很容易误以为“没生效”。
为什么 flatten() 看起来没 flatten 完?
ThinkPHP 的 Collection(v6.x)中 flatten() 方法等价于「浅扁平化」:它只把第一层的子数组(或 Collection)元素取出,不会递归处理子数组内部的嵌套。
常见错误现象:
输入 [[1, [2, 3]], [4, [5, [6]]]],调用 ->flatten() 后得到 [1, [2, 3], 4, [5, [6]]],而非预期的 [1, 2, 3, 4, 5, 6]。
- 这是设计行为,不是 bug
- 底层调用的是 PHP 原生
array_merge(...$arrays)展开逻辑,不递归 - 若需深度扁平,必须手动实现或封装递归逻辑
如何真正实现深度扁平(递归 flatten)?
ThinkPHP 没提供内置深度 flatten(),但可以用 map() + 递归闭包,或直接写个辅助函数。推荐以下轻量方案:
// 示例:深度扁平化 Collection
$collection = collect([[1, [2, 3]], [4, [5, [6]]]]);
$deepFlatten = function ($item) use (&$deepFlatten) {
return is_array($item) ? array_merge(...array_map($deepFlatten, $item)) : [$item];
};
$result = collect(array_merge(...$collection->map($deepFlatten)->all()));
// $result 是 collect([1, 2, 3, 4, 5, 6])
- 注意:
array_merge(...$arr)要求$arr是索引数组,否则会丢键;Collection::all()保证返回索引数组 - 避免用
foreach手动 push,性能差且易错 - 如果数据含对象、
Collection实例,需额外判断is_iterable()并调用->toArray()
替代方案:用 PHP 8.1+ 的 array_reduce + array_merge
更简洁、无闭包引用问题,适合简单场景:
立即学习“PHP免费学习笔记(深入)”;
$deepFlattenArray = function (array $arr) use (&$deepFlattenArray): array {
return array_reduce($arr, function ($carry, $item) use ($deepFlattenArray) {
return $carry = array_merge($carry, is_array($item) ? $deepFlattenArray($item) : [$item]);
}, []);
};
$result = collect($deepFlattenArray($originalArray));
- 比
map+array_merge(...)更易读,兼容性更好 - 注意:PHP array_reduce 第三个参数(initial)需显式传空数组
[],否则报错 - 该函数不处理
null或非数组类型,使用前建议加is_array()校验
真正容易被忽略的是:ThinkPHP 的 flatten() 和 Laravel 的同名方法行为一致,但 Laravel 文档明确写了 “flattens only one level deep”,而 ThinkPHP 官方文档没强调这点——结果就是很多人在多层嵌套时反复调试却找不到原因。



















