
本文介绍如何将嵌套 json 结构(含 children 层级)递归扁平化,并确保每个元素都以 {"name": "x"} 的标准对象格式输出,解决原始代码中部分节点丢失 name 包裹、类型不一致的问题。
本文介绍如何将嵌套 json 结构(含 children 层级)递归扁平化,并确保每个元素都以 {"name": "x"} 的标准对象格式输出,解决原始代码中部分节点丢失 name 包裹、类型不一致的问题。
在处理树形结构数据(如组织架构、菜单、分类目录)时,常需将多层嵌套的 PHP 数组“压平”为一维列表,同时保持语义一致性。原始实现存在两个关键缺陷:
- 逻辑混淆:错误地混合了键名判断(如 array_key_exists("children", $value))与值类型处理,导致非数组项(如字符串 "A")被直接推入结果,而未包装为 ["name" => "A"];
- 结构断裂:未统一输出格式,造成结果中混杂字符串与关联数组,破坏 JSON 兼容性与前端消费的稳定性。
正确做法是:忽略键名,专注值的语义层级——只要遇到 name 字段(无论在哪一层),就提取其值并标准化封装;对 children 数组则递归遍历,跳过无关字段。
以下是推荐的健壮实现:
<?php $json = '[
{
"name": "A",
"children": [
{
"name": "B",
"children": [
{ "name": "C" },
{
"name": "D",
"children": [
{ "name": "E" },
{ "name": "F" }
]
}
]
},
{ "name": "G" }
]
},
{ "name": "H" }
]';
$data = json_decode($json, true);
function flattenByName(array $array): array {
$result = [];
foreach ($array as $item) {
// 确保当前项是数组且包含 'name' 键
if (is_array($item) && isset($item['name'])) {
// 提取 name 值并标准化为 {"name": "..."}
$result[] = ['name' => $item['name']];
// 若存在 children,则递归处理
if (isset($item['children']) && is_array($item['children'])) {
$result = array_merge($result, flattenByName($item['children']));
}
}
// 忽略不含 name 的项(如空数组、其他字段),保证结果纯净
}
return $result;
}
echo json_encode(flattenByName($data), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
?>
输出结果:
[
{"name":"A"},
{"name":"B"},
{"name":"C"},
{"name":"D"},
{"name":"E"},
{"name":"F"},
{"name":"G"},
{"name":"H"}
]
✅ 优势说明:
- 语义精准:只处理含 name 键的有效节点,避免误提 children 或其他字段;
- 结构安全:强制返回统一的关联数组格式,兼容 json_encode() 输出标准 JSON 对象;
- 可扩展性强:若后续需提取 id、type 等字段,只需在 $result[] = [...] 中追加即可;
- 健壮性高:使用 isset() 替代 array_key_exists(),避免对 null 值的误判,且显式检查 is_array($item['children']) 防止警告。
⚠️ 注意事项:
- 此函数假设输入数据符合“每层节点必有 name 键”的业务约定;若存在缺失 name 的合法节点,应先清洗数据或改用更宽松的提取策略(如 ?? '' 默认值);
- 深度嵌套可能导致栈溢出,生产环境建议添加递归深度限制(例如传入 $depth 参数并校验);
- 如需保留原始键路径(如 A > B > C),可扩展为带 $path 参数的版本,用于生成面包屑或全路径标识。
通过该方案,您能可靠地将任意深度的树状 name 数据转化为扁平、规范、可序列化的对象列表,为前端渲染、API 响应或数据分析提供坚实基础。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











