必须手写递归函数find_all_keys(),因array_walk_recursive()不提供键名;函数接收数组和目标键名,遍历中匹配键名则收集值,子数组递归合并结果;需处理对象转数组及递归深度限制。

递归遍历多维数组找所有 key 值,别用 array_walk_recursive()
array_walk_recursive() 看起来省事,但它会跳过键名(只遍历值),根本拿不到嵌套层里的 key 对应的键名本身。你要的是“所有层级中名为 id 的键所对应的值”,不是“所有值里等于 id 的那个”。所以必须手写递归,控制键和值的访问权限。
手写递归函数:参数设计和终止条件要盯紧
核心是保持对当前层级键名的可见性。函数至少接收两个参数:$array(当前子数组)和 $target_key(要找的键名)。返回一个扁平数组收集所有匹配值。
- 每次进入函数先判断
is_array($array),非数组直接 return [],避免警告 - 遍历用
foreach ($array as $key => $value),确保$key可见 - 如果
$key === $target_key,就把$value推进结果数组 - 如果
$value是数组,递归调用自身,并把结果 merge 进去(不能用+=,会覆盖数字键)
function find_all_keys($array, $target_key) {
if (!is_array($array)) return [];
$results = [];
foreach ($array as $key => $value) {
if ($key === $target_key) {
$results[] = $value;
}
if (is_array($value)) {
$results = array_merge($results, find_all_keys($value, $target_key));
}
}
return $results;
}
遇到对象或 JSON 解析后混合结构怎么办
PHP 里 json_decode($json, false) 返回对象,foreach 无法直接遍历对象属性。这时候要么统一转成数组(加 true 参数),要么改写函数支持对象。
- 最简单:调用前强制转数组,
find_all_keys((array) $data, 'id') - 如果必须处理对象,需在函数开头加判断:
if (is_object($array)) $array = (array) $array; - 注意:对象转数组后,私有/受保护属性会带类名前缀(如
\u0000ClassName\u0000prop),这种 key 不会匹配你传的纯字符串'id',得提前清理或换思路
性能和深度限制要注意的几个点
PHP 默认递归限制是 100 层(xdebug.max_nesting_level 或 zend_extension 设置),超了会报 Fatal error: Maximum function nesting level of '100' reached。这不是代码错,是配置卡住了。
立即学习“PHP免费学习笔记(深入)”;
- 确认数据真实嵌套深度,用
count($array, COUNT_RECURSIVE)辅助估算,但不等价于层数 - 生产环境别盲目调高
max_nesting_level,先检查是否出现无限递归(比如数组引用自身) - 超大数组建议加深度计数参数,防止失控:
function find_all_keys($array, $target_key, $depth = 0) { if ($depth > 50) return []; ... }
真正难的不是写出递归,而是判断哪些 key 是你“想要的”——比如 'id' 在某些层是主键,在另一层是外键,语义不同。这时候光靠 key 名不够,得结合路径或上下文,那就要改造成带路径追踪的版本了。



















