PHP递归构建JSON树形结构子元素重复绑定父元素的解决方法
解决PHP递归构建树形结构时子元素重复绑定问题
问题根源
你遇到的重复绑定问题,核心错误是用level字段判断父子关系,而不是用明确的父节点关联ID(比如parent_id)。level仅表示元素的层级深度,相同层级的元素可能属于不同的父节点,只靠level匹配会把所有同层级元素挂到每个上层节点下,导致重复。
修改方案
前提:确保数据有明确的父关联字段
首先,你的扁平JSON数据需要包含parent_id字段(或类似字段),用来明确每个元素归属的父节点ID。比如原始数据格式应该是:
$flatData = [ ['id' => 1, 'level' => 1, 'name' => '父元素1', 'parent_id' => 0], ['id' => 2, 'level' => 1, 'name' => '父元素2', 'parent_id' => 0], ['id' => 3, 'level' => 2, 'name' => '子元素1', 'parent_id' => 1], ['id' => 4, 'level' => 2, 'name' => '子元素2', 'parent_id' => 2], ];
修正递归函数
修改递归逻辑,用parent_id匹配父子关系,而不是level:
function buildTree($data, $parentId = 0) { $tree = []; foreach ($data as $item) { // 只筛选父ID等于当前传入值的元素 if ($item['parent_id'] == $parentId) { // 递归查找该元素的子节点(父ID为当前元素ID) $children = buildTree($data, $item['id']); if (!empty($children)) { $item['children'] = $children; } $tree[] = $item; } } return $tree; } // 调用示例 $tree = buildTree($flatData); print_r(json_encode($tree, JSON_PRETTY_PRINT));
如果数据没有parent_id的预处理方案
如果原始数据只有level和id,可以先通过层级顺序推断父节点,给每个元素添加parent_id:
$processedData = []; $levelStack = []; foreach ($flatData as $item) { $currentLevel = $item['level']; // 维护层级栈:弹出栈中层级>=当前层级的元素,栈顶即为父节点 while (!empty($levelStack) && end($levelStack)['level'] >= $currentLevel) { array_pop($levelStack); } // 根节点父ID设为0,其他取栈顶元素的ID $item['parent_id'] = empty($levelStack) ? 0 : end($levelStack)['id']; $levelStack[] = $item; $processedData[] = $item; } // 再用修正后的buildTree处理 $tree = buildTree($processedData);
大数据量优化方案
如果数据量较大,每次递归遍历全量数据效率低,可以先按parent_id分组,减少遍历次数:
function buildTreeOptimized($data) { // 先按parent_id分组,构建映射表 $parentMap = []; foreach ($data as $item) { $parentId = $item['parent_id'] ?? 0; $parentMap[$parentId][] = $item; } // 闭包递归构建树形结构 $build = function($parentId) use (&$build, &$parentMap) { $tree = []; foreach ($parentMap[$parentId] ?? [] as $item) { $children = $build($item['id']); if (!empty($children)) { $item['children'] = $children; } $tree[] = $item; } return $tree; }; return $build(0); }
正确输出示例
执行修正后的代码,每个子元素只会归属到对应的父节点:
[ { "id": 1, "level": 1, "name": "父元素1", "parent_id": 0, "children": [ { "id": 3, "level": 2, "name": "子元素1", "parent_id": 1 } ] }, { "id": 2, "level": 1, "name": "父元素2", "parent_id": 0, "children": [ { "id": 4, "level": 2, "name": "子元素2", "parent_id": 2 } ] } ]
内容的提问来源于stack exchange,提问作者Alex Boyarchuk
相关产品推荐
相关产品推荐

