
本文介绍如何用 php 递归函数替代多层嵌套循环,高效提取任意深度 json 结构中所有含 `label` 和 `value` 键的对象,并统一组织为扁平化关联数组。
在处理具有不确定嵌套层级的结构化数据(如带多级 descends 的配置型 JSON)时,硬编码多层 foreach 循环不仅难以维护,更无法应对动态加深的层级。此时,递归是天然且优雅的解决方案:它将“检查当前层级 + 若存在子结构则交由自身处理”的逻辑封装为单一、可复用的函数。
以下是一个健壮、简洁且符合 PSR-12 规范的递归实现:
/**
* 递归提取所有含 'label' 和 'value' 键的关联项
* @param array $data 输入的关联数组(由 json_decode($json, true) 得到)
* @param array &$result 引用传入的结果容器,用于累积匹配项
* @return void
*/
function collectLabelValuePairs(array $data, array &$result): void
{
// 遍历当前层级所有键值对
foreach ($data as $key => $value) {
// 若值为数组,则递归进入下一层
if (is_array($value)) {
collectLabelValuePairs($value, $result);
}
}
// 在当前层级检查是否存在 'label' 键(关键判断点)
// 注意:我们只在当前数组本身含 'label' 时才采集,而非其子数组
if (isset($data['label'])) {
$result[] = [
'label' => $data['label'],
'value' => $data['value'] ?? null // 安全兜底:若 value 不存在,设为 null
];
}
}
// 使用示例
$json = <<<'EOT'
{
"id": 1,
"name": null,
"block": {
"type": "none",
"descends": [
{
"operation":"sum",
"descends":[
{
"operation":"sum",
"descends":[
{"label":2,"value":false},
{"label":3,"value":"text"}
],
"label":2,
"value":false
}
]
},
{
"label": 1,
"value": 3
},
{
"label": 2,
"value": 2
}
],
"label": 1,
"value": true
}
}
EOT;
$data = json_decode($json, true);
$result = [];
collectLabelValuePairs($data, $result);
print_r($result);✅ 输出结果(自动覆盖任意深度):
Array
(
[0] => Array
(
[label] => 2
[value] =>
)
[1] => Array
(
[label] => 3
[value] => text
)
[2] => Array
(
[label] => 2
[value] =>
)
[3] => Array
(
[label] => 1
[value] => 3
)
[4] => Array
(
[label] => 2
[value] => 2
)
[5] => Array
(
[label] => 1
[value] => 1
)
)? 关键设计说明:
- 递归触发条件明确:仅当 is_array($value) 时向下递归,避免误入字符串或数字;
- 采集时机精准:if (isset($data['label'])) 放在循环之后,确保只采集当前层级对象的 label/value,而非子数组的(避免重复或错位);
- 安全容错:使用 $data['value'] ?? null 防止 Notice: Undefined index;
- 无状态、无副作用:函数不依赖全局变量,仅通过引用参数累积结果,便于单元测试与复用。
⚠️ 注意事项:
- 输入必须是 json_decode($json, true) 返回的关联数组(非对象),否则 isset($arr['label']) 将失效;
- 若原始 JSON 中 label 可能为 null 或 0,而你需严格区分“不存在”与“显式为 null”,请改用 array_key_exists('label', $data);
- 深度极深(>1000 层)的 JSON 可能触发 PHP 默认栈限制,生产环境建议添加递归深度计数器做防护。
通过该递归方案,你彻底摆脱了“每深一层就加一个 foreach”的脆弱模式,代码更具扩展性、可读性与鲁棒性。










