php二维数组转树形结构需用id/pid构建引用映射,先遍历建立$refs[id]→&item引用,再按pid归位子节点到children,最后取pid为根标识(如0/null)的项作根;不可用array_merge等扁平化函数,因其破坏父子关系。

PHP 二维数组转一维树形结构,本质不是“扁平化”,而是按父子关系(如 id / pid)重新组织成嵌套数组。直接用 array_merge 或 array_values 不行,必须构建层级引用关系。
怎么用 id 和 pid 构建树形嵌套数组
前提是原始二维数组每项含 id 和 pid(父级 ID),且 pid 指向另一个元素的 id。核心思路是:先建立所有节点的引用映射,再按 pid 归位子节点。
- 遍历一遍原数组,用
$refs[$item['id']] = &$item建立 ID → 引用映射 - 再遍历一次,若
$item['pid'] !== 0(或 null/空字符串),则把当前$item推入$refs[$item['pid']]['children'][] - 最后筛选出所有
pid === 0(或 null)的项作为根节点
注意:必须用引用(&$item),否则第二次遍历时无法修改原始数组结构;pid 的“根标识”需根据实际数据确认,不一定是 0,也可能是 null、'' 或 -1。
为什么不能用 array_column + foreach 简单拼接
array_column 只能提取列或重键,无法表达父子嵌套逻辑。常见错误是试图用 foreach 遍历并手动 unset 子项来“降维”,结果要么丢失层级,要么产生重复引用或死循环。
立即学习“PHP免费学习笔记(深入)”;
- 二维转一维(扁平化)用
array_merge(...$arr)或array_reduce即可,但那是破坏层级的线性展开 - 树形结构是“一维变多维”,方向相反,强行用扁平化函数会丢掉父子关系
- 如果原数组没有
pid字段,仅靠键名(如'user.0.name')想转树形,那属于“路径解析”,得先explode('.', $key)再逐层赋值,和id/pid场景完全不同
如何处理带深度限制或排序需求
构建完基础树后,若需控制最大深度或按字段排序,应在构建完成后再递归处理,不要在构建过程中混入逻辑。
- 深度限制:写个递归函数,在每层调用前检查当前层级,超限则清空
children - 同级排序:对每个节点的
children数组调用usort($children, fn($a, $b) => $a['sort'] $b['sort']) - 避免在构建循环里做
usort—— 每次插入都重排,时间复杂度飙升,且可能因引用未就绪导致空数组警告
真正容易被忽略的是 pid 类型一致性:数据库查出的 pid 可能是字符串 "0",而代码里判断用的是 === 0,结果根节点被当成子节点挂到不存在的 $refs["0"] 下。上线前务必检查 var_dump(array_unique(array_column($data, 'pid'))) 看实际值类型。











