
本文介绍一种递归遍历无限嵌套数组的方法,将具有层级结构的资源数据(如带 @id 的树形结构)转换为扁平数组,并准确记录每个资源的直接父级标识符,适用于权限、菜单、分类等树状数据的序列化处理。
本文介绍一种递归遍历无限嵌套数组的方法,将具有层级结构的资源数据(如带 `@id` 的树形结构)转换为扁平数组,并准确记录每个资源的直接父级标识符,适用于权限、菜单、分类等树状数据的序列化处理。
在实际开发中(例如构建动态菜单系统或 RBAC 权限模型),我们常需将深度嵌套的资源结构(如多层 resource 嵌套)转化为便于前端消费或数据库存储的扁平格式。核心需求是:每个子资源必须明确其直接父级 @id,顶层资源父级为 null。
原始结构示例:
$array = [
0 => [
'@id' => 'Authorization',
'@sortOrder' => '1',
'resource' => [
'@id' => 'Authorization2',
'@title' => 'Authorization2',
],
],
];
目标输出应为:
$resources = [
0 => ['parent' => null, 'resource' => 'Authorization'],
1 => ['parent' => 'Authorization', 'resource' => 'Authorization2'],
];
关键在于递归过程中传递并更新当前父级上下文。以下为优化后的健壮实现:
public function array_values_recursive($array, $parent = null) {
$flat = [];
$index = 0;
foreach ($array as $key => $value) {
if (is_array($value)) {
// 若当前数组自身含 '@id',则它是新层级的父节点,后续子项以此为 parent
if (isset($array['@id'])) {
$flat = array_merge($flat, $this->array_values_recursive($value, $array['@id']));
} else {
// 否则沿用上层传入的 parent(如 resource 下的深层嵌套)
$flat = array_merge($flat, $this->array_values_recursive($value, $parent));
}
} elseif ($key === '@id') {
// 提取当前层级的资源 ID,并关联 parent
$item = ['resource' => $value];
if ($parent !== null) {
$item['parent'] = $parent;
} else {
$item['parent'] = null;
}
$flat[$index++] = $item;
}
}
return $flat;
}
✅ 使用说明与注意事项:
- 该函数严格依赖 @id 字段作为资源唯一标识和父子关系锚点;确保源数据中所有需扁平化的节点均包含此键。
- resource 键名不参与逻辑判断,仅作为数据容器——真正决定层级的是 @id 是否存在于当前数组层级。
- 若存在同名 @id 跨层级重复(非典型),建议预先校验唯一性,避免语义混淆。
- 性能方面:对超深嵌套(>100 层)建议增加递归深度限制或改用迭代栈模拟,防止 PHP 栈溢出。
最终调用方式:
$result = $this->array_values_recursive($originalArray); // 输出即为符合要求的扁平化资源列表
此方案兼顾可读性、可维护性与扩展性,可直接集成至 Laravel、Symfony 等框架的服务类中,亦可轻松适配 JSON API 或前端 Tree 组件的数据预处理流程。










