處理多維數組(嵌套數組)時,遞歸是最自然的遍歷與轉換方式。本文通過「HTML 特殊字符轉義」實例,演示遞歸處理多維數組的核心模式與變體。
<?php
// 原始數據:包含嵌套數組的混合結構
$arr = [
['< 小剛>', '< 小曉>'],
'< 小飛>',
'< 小李>',
'< 小紅>'
];
/**
* 遞歸處理數組中的字符串值
* @param mixed $value 數組或標量值
* @return mixed 處理後的值(保持原結構)
*/
function arrContentReplact($value) {
// 基線條件:非數組直接處理
if (!is_array($value)) {
return str_replace(['<', '>'], ['{', '}'], $value);
}
// 遞歸條件:遍歷數組元素
foreach ($value as $key => $item) {
// 關鍵:引用賦值保持原數組結構
$value[$key] = arrContentReplact($item);
}
return $value;
}
// 執行處理
$arr3 = arrContentReplact($arr);
// 輸出結果
echo "<pre>";
print_r($arr3);
echo "</pre>";
/*
輸出結果:
Array
(
[0] => Array
(
[0] => { 小剛}
[1] => { 小曉}
)
[1] => { 小飛}
[2] => { 小李}
[3] => { 小紅}
)
*/
?>
<?php
/**
* 通用遞歸數組處理模板
*/
function recursiveArrayProcess($data, callable $scalarHandler, callable $arrayHandler = null) {
if (is_array($data)) {
$result = [];
foreach ($data as $key => $value) {
// 遞歸處理子元素
$processed = recursiveArrayProcess($value, $scalarHandler, $arrayHandler);
// 可選:數組層級處理(如過濾、排序、鍵名轉換)
if ($arrayHandler) {
$processed = $arrayHandler($key, $processed);
}
$result[$key] = $processed;
}
return $result;
}
// 標量值處理
return $scalarHandler($data);
}
// 使用示例:同樣的字符替換
$processed = recursiveArrayProcess($arr, function($scalar) {
return str_replace(['<', '>'], ['{', '}'], $scalar);
});
?>
<?php
function arrayWalkRecursiveRef(array &$array, callable $callback) {
array_walk_recursive($array, function(&$value, $key) use ($callback) {
$value = $callback($value, $key);
});
}
// 使用
arrayWalkRecursiveRef($arr, function(&$value) {
$value = str_replace(['<', '>'], ['{', '}'], $value);
});
// $arr 直接被修改
?>
<?php
function flattenArray(array $array, string $prefix = ''): array {
$result = [];
foreach ($array as $key => $value) {
$newKey = $prefix ? "$prefix.$key" : (string)$key;
if (is_array($value)) {
$result = array_merge($result, flattenArray($value, $newKey));
} else {
$result[$newKey] = $value;
}
}
return $result;
}
// 輸出: ['0.0' => '{ 小剛}', '0.1' => '{ 小曉}', '1' => '{ 小飛}', ...]
?>
<?php
function recursiveWithDepthLimit($data, callable $fn, int $maxDepth = 100, int $currentDepth = 0) {
if ($currentDepth >= $maxDepth) {
throw new RuntimeException("遞歸深度超過限制: $maxDepth");
}
if (is_array($data)) {
foreach ($data as $key => $value) {
$data[$key] = recursiveWithDepthLimit($value, $fn, $maxDepth, $currentDepth + 1);
}
return $data;
}
return $fn($data);
}
?>
<?php
function recursiveGenerator($data) {
if (is_array($data)) {
foreach ($data as $value) {
yield from recursiveGenerator($value);
}
} else {
yield $data;
}
}
// 只遍歷不構建新數組,極省內存
foreach (recursiveGenerator($hugeArray) as $scalar) {
processScalar($scalar);
}
?>
<?php
class ArrayRecursive {
/** 映射:對每個標量值應用回調 */
public static function map(array $array, callable $callback): array {
return array_map(function($v) use ($callback) {
return is_array($v) ? self::map($v, $callback) : $callback($v);
}, $array);
}
/** 遍歷:對每個標量值執行回調(不改變結構) */
public static function walk(array &$array, callable $callback): void {
array_walk_recursive($array, $callback);
}
/** 過濾:移除不符合條件的標量值(保留結構) */
public static function filter(array $array, callable $callback): array {
return array_filter($array, function($v) use ($callback) {
return is_array($v) ? !empty(self::filter($v, $callback)) : $callback($v);
});
}
/** 搜索:查找滿足條件的首個值路徑 */
public static function search(array $array, callable $callback): ?array {
foreach ($array as $key => $value) {
if (is_array($value)) {
if ($path = self::search($value, $callback)) {
return array_merge([$key], $path);
}
} elseif ($callback($value, $key)) {
return [$key];
}
}
return null;
}
/** 扁平化:多維轉一維(鍵名用分隔符連接) */
public static function flatten(array $array, string $separator = '.'): array {
$result = [];
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $key => $value) {
if (!$iterator->hasChildren()) {
$path = [];
for ($i = 0; $i <= $iterator->getDepth(); $i++) {
$path[] = $iterator->getSubIterator($i)->key();
}
$result[implode($separator, $path)] = $value;
}
}
return $result;
}
}
// 使用
$clean = ArrayRecursive::map($dirtyArr, fn($v) => htmlspecialchars($v, ENT_QUOTES, 'UTF-8'));
$flat = ArrayRecursive::flatten($nestedConfig);
?>
| 方案 | 最大深度 | 內存效率 | 適用場景 |
|---|---|---|---|
| 原生遞歸函數 | ~100-200 (PHP 默認棧) | 中等 | 淺層嵌套、簡單邏輯 |
| array_walk_recursive | 同上 | 高(原地修改) | 只需修改值、不改結構 |
| RecursiveIteratorIterator | 無限制(堆內存) | 高(迭代器) | 深層嵌套、大數據量 |
| 生成器 yield from | 無限制 | 極高(懶加載) | 只需遍歷、不構建結果 |
| 手動棧模擬遞歸 | 無限制 | 可控 | 極深嵌套、需精確控制 |
<?php
function iterativeArrayProcess(array $array, callable $scalarFn): array {
$stack = [['array' => &$array, 'keys' => []]];
$result = [];
$refs = [&$result]; // 引用鏈
while ($stack) {
$frame = array_pop($stack);
$currentArray = &$frame['array'];
$currentKeys = $frame['keys'];
foreach ($currentArray as $key => &$value) {
$newKeys = array_merge($currentKeys, [$key]);
if (is_array($value)) {
// 創建結果數組的引用位置
$target = &$result;
foreach ($newKeys as $k) {
if (!isset($target[$k])) $target[$k] = [];
$target = &$target[$k];
}
$stack[] = ['array' => &$value, 'keys' => $newKeys];
} else {
// 設置處理後的值
$target = &$result;
foreach ($newKeys as $k) {
$target = &$target[$k];
}
$target = $scalarFn($value);
}
}
}
return $result;
}
?>
PHP 處理多維數組遞歸的核心模式是:「判斷類型 → 標量處理 / 數組遞歸 → 組合結果」。現代開發優先選擇 RecursiveIteratorIterator 或 array_walk_recursive,複雜邏輯封裝為工具類。注意棧深度限制,大數據量改用迭代器或生成器模式。