
本文介绍一种递归遍历无限嵌套资源数组的方法,将每个 @id 值提取为独立条目,并自动记录其直接父级 @id(顶层节点父级为 null),最终生成结构清晰、可直接用于权限树渲染或数据绑定的扁平化数组。
本文介绍一种递归遍历无限嵌套资源数组的方法,将每个 `@id` 值提取为独立条目,并自动记录其直接父级 `@id`(顶层节点父级为 `null`),最终生成结构清晰、可直接用于权限树渲染或数据绑定的扁平化数组。
在构建权限系统、菜单导航树或配置驱动型后台时,常需将深度嵌套的资源结构(如带 resource 子数组的层级数据)转换为扁平、带父子关系标记的线性数组。核心挑战在于:准确识别每个节点的“直接父级”——即其所在数组的上一层 @id,而非逻辑语义上的祖先节点。
以下是一个健壮、可复用的 PHP 递归实现:
public function array_values_recursive($array, $parent = null) {
$flat = [];
$i = 0;
foreach ($array as $key => $value) {
if (is_array($value)) {
// 若当前数组自身含有 '@id',说明它是新层级的父节点 → 将其 ID 作为下层递归的 parent
if (array_key_exists('@id', $array)) {
$flat = array_merge($flat, $this->array_values_recursive($value, $array['@id']));
}
// 否则沿用上一层传入的 parent(如 resource 内部继续嵌套)
else {
$flat = array_merge($flat, $this->array_values_recursive($value, $parent));
}
} else {
// 仅当键为 '@id' 时才提取为有效资源项
if ($key === '@id') {
$item = ['resource' => $value];
if ($parent !== null) {
$item['parent'] = $parent;
// 可选:按需添加父级别名字段(如示例中的 'Authorization' => 'Authorization')
$item[$parent] = $parent;
} else {
$item['parent'] = null;
}
$flat[$i] = $item;
$i++;
}
}
}
return $flat;
}
✅ 关键设计说明:
- 双参数递归:$array(当前层级数据) + $parent(上一层 @id,初始为 null),确保父子关系链不丢失;
- 上下文感知:通过 array_key_exists('@id', $array) 判断当前数组是否为“有身份的父容器”,从而决定是否更新 parent;
- 精准提取:只对 @id 键做扁平化输出,避免误提 @sortOrder、@title 等辅助字段;
- 结构兼容性:输出格式严格匹配需求——顶层节点 parent => null,子节点含 parent => 'ParentId' 及可选同名映射字段。
⚠️ 注意事项:
- 该函数假设输入数据中 @id 是唯一且稳定标识符;若存在重复 @id,父子关系将出现歧义,建议预处理去重或使用复合键;
- 如需保留原始索引或排序信息(如 @sortOrder),可在 $item 中一并注入:$item['sortOrder'] = $array['@sortOrder'] ?? null;
- 对超深层嵌套(>100 层),注意 PHP 默认 xdebug.max_nesting_level 限制,必要时调整配置。
此方案已验证支持任意深度嵌套,例如:
// 输入含三级嵌套 [ ['@id' => 'A', 'resource' => ['@id' => 'B', 'resource' => ['@id' => 'C']]] ] // 输出 [ ['parent' => null, 'resource' => 'A'], ['parent' => 'A', 'resource' => 'B', 'A' => 'A'], ['parent' => 'B', 'resource' => 'C', 'B' => 'B'] ]
通过该方法,你可将复杂嵌套结构转化为前端易消费、后端易索引的标准扁平数组,显著提升权限校验、树形组件渲染与 API 数据一致性。










