关键不是递归而是构建父子映射:先遍历建$id→$item映射表,再遍历将节点挂载到$map[$item['parent_id']]['children'],最后筛选根节点;需注意parent_id类型一致、编码UTF-8、防环引用及路径预生成。

递归函数里怎么判断子节点并挂载到 parent_id 对应的 children 数组
关键不是“递归”,而是构建父子关系映射。直接遍历一遍原始数组,用 $id 作键缓存所有节点,再遍历一次,把 $item['parent_id'] 存在的节点推入其 children 数组——这比边递归边查找快得多,也避免重复遍历。
常见错误是:每次递归都全量扫描数组找子项,O(n²) 复杂度,1000 条数据就明显卡顿。
- 先用
foreach建立$map[$id] = $item映射表 - 再遍历所有项,若
$item['parent_id']不为null或0,则追加到$map[$item['parent_id']]['children'][] - 最后筛选出
parent_id为空/零的项作为根节点(注意业务中可能是null、0或字符串"0")
JSON 编码时中文乱码或 \uXXXX 转义怎么处理
json_encode() 默认不转义中文,但前提是输入字符串本身是 UTF-8 编码。如果原始数组含 GBK 或其他编码的字段,会直接输出 \uXXXX 或乱码。
不要在 json_encode() 里硬加 JSON_UNESCAPED_UNICODE 参数来“解决”乱码——它只控制是否转义中文,不解决编码问题。
立即学习“PHP免费学习笔记(深入)”;
- 确认数据库连接、查询结果、文件读取全程使用 UTF-8(如 PDO 连接加
charset=utf8mb4) - 用
mb_detect_encoding($str, ['UTF-8', 'GBK'], true)检查单个字段编码,非 UTF-8 则用mb_convert_encoding($str, 'UTF-8', 'GBK') - 最终调用
json_encode($tree, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
递归生成结构时遇到深层嵌套导致 PHP 崩溃或超时
不是代码写错了,大概率是数据存在环引用(比如 A 的 parent_id 是 B,B 的 parent_id 又指回 A),或者层级过深(>100 层)触发了 PHP 的默认栈限制或 max_execution_time。
别依赖 try-catch 捕获致命错误——Fatal error: Maximum function nesting level 无法被常规异常机制捕获。
- 建临时
$visited = []记录已进入的$id,每次递归前检查是否重复出现 - 加深度参数
$depth,超过阈值(如 50)立即return null并记录 warning - 生产环境建议改用上面提到的“两次遍历 + 映射表”方式,彻底规避递归调用栈
前端需要扁平化 ID 路径(如 "1.3.7")但后端只返回嵌套结构
如果前端渲染树形控件(如 Ant Design Tree 或 Element Plus ElTree)需要每个节点带完整路径用于搜索或高亮,这个路径不适合在前端拼接——尤其是节点可能展开/收起、异步加载。
应在 PHP 构建嵌套结构时一并注入,而不是事后遍历 JSON 字符串去 patch。
- 在挂载
children的同时,传入当前路径(如初始为'',子节点为$path ? $path . '.' . $id : (string)$id) - 把路径存为
$item['path'] = $currentPath,确保和children同步生成 - 避免用
json_encode()后再正则替换——JSON 中字段名、字符串值都可能含点号,极易误伤
parent_id 的类型一致性:数据库里是 INT,PHP 从 $_POST 或 JSON body 接收时可能变成 string,导致 $map[$item['parent_id']] === null 查不到。强制类型转换或统一用 (int)$item['parent_id'] 再查映射表,比事后 debug 快得多。



















