如何用带通配符的白名单路径递归过滤多维数组?
PHP 递归过滤多维数组(支持路径白名单与通配符)
需求说明
实现通用递归函数,根据指定路径白名单过滤深度不确定的多维数组,保留路径对应的键值对,重点支持索引数组的通配符*处理(对数组内所有元素应用后续路径规则)。
实现代码
function filterArrayByPath(array $array, array $paths): array { $result = []; foreach ($paths as $path) { $current = &$array; $target = &$result; $pathLength = count($path); for ($i = 0; $i < $pathLength; $i++) { $key = $path[$i]; // 处理通配符:匹配索引数组的所有元素 if ($key === '*') { if (!is_array($current) || isIndexArray($current)) { foreach ($current as $index => $item) { $remainingPath = array_slice($path, $i + 1); if (!empty($remainingPath)) { // 递归过滤子元素,复用当前函数逻辑 $filteredItem = filterArrayByPath([$item], [$remainingPath])[$index] ?? []; if (!empty($filteredItem)) { $target[$index] = $filteredItem; } } else { $target[$index] = $item; } } } break; } // 原数组中无此键,跳过当前路径 if (!isset($current[$key])) { break; } // 初始化结果数组的对应层级 if (!isset($target[$key])) { $target[$key] = is_array($current[$key]) ? [] : $current[$key]; } // 到达路径末尾,直接赋值 if ($i === $pathLength - 1) { $target[$key] = $current[$key]; } else { // 继续深入数组层级 $current = &$current[$key]; $target = &$target[$key]; } } } // 清理结果中的空数组节点 array_walk_recursive($result, function (&$value) { if (is_array($value) && empty($value)) { $value = null; } }); $result = array_filter($result, function ($value) { return !is_null($value) && (!is_array($value) || !empty($value)); }); return $result; } // 兼容PHP<8.1的索引数组判断函数 function isIndexArray(array $array): bool { if (empty($array)) { return true; } return array_keys($array) === range(0, count($array) - 1); }
关键逻辑说明
- 路径层级遍历:逐条处理白名单路径,同步构建结果数组的对应层级,确保只保留指定路径的键值对。
- 通配符处理:当路径段为
*时,判断当前数组是否为索引数组(无自定义键),遍历所有元素并递归应用剩余路径的过滤规则,实现批量处理数组内的所有子元素。 - 空节点清理:递归清除结果中的空数组节点,避免残留无用的空结构。
- 递归复用:通配符场景下递归调用自身,复用过滤逻辑,保证深层数组处理的一致性。
测试示例
$originalArray = array( 'key1' => array( 'key1' => 'value1', 'key2' => 'value2', ), 'key2' => array( 'key1' => 'value3', 'key2' => 'value4', 'key3' => array( 'key1' => 'value5', 'key2' => array( 'key1' => 'value6', 'key2' => 'value', ), ), ), 'key3' => array( "key1" => "value1", "key2" => array( array( 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value2', ), array( 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', ), ) ), ); $pathsToRetain = array( array('key1', 'key1'), array('key2', 'key1'), array('key2', 'key3', 'key1'), array('key2', 'key3', 'key2', 'key1'), array("key3", "key2", "*", 'key1'), array("key3", "key2", "*", 'key3') ); $result = filterArrayByPath($originalArray, $pathsToRetain); print_r($result);
预期输出
Array ( [key1] => Array ( [key1] => value1 ) [key2] => Array ( [key1] => value3 [key3] => Array ( [key1] => value5 [key2] => Array ( [key1] => value6 ) ) ) [key3] => Array ( [key2] => Array ( [0] => Array ( [key1] => value1 [key3] => value2 ) [1] => Array ( [key1] => value1 [key3] => value3 ) ) ) )
内容的提问来源于stack exchange,提问作者ReaperSoon
相关产品推荐
相关产品推荐

