多維陣列遍歷是常見需求,遞迴是最直觀的解法。本文提供標準遞迴實作、迭代器替代方案與深度過大時的效能優化建議。
<?php
/**
* 遞迴遍歷多維陣列,印出所有非陣列值
* @param array $arr
* @param int $depth 當前深度 (除錯用)
*/
function arrayRecursivePrint(array $arr, int $depth = 0) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
// 可選:印出鍵名層級
// echo str_repeat(' ', $depth) . "[$key] => Array\n";
arrayRecursivePrint($val, $depth + 1);
} else {
echo str_repeat(' ', $depth) . "[$key] => $val\n";
}
}
}
// 測試資料
$data = [
1 => [11, 12, 13, 14 => [141, 142]],
2, 3, 4, 5
];
echo "原始結構:\n";
print_r($data);
echo "\n遍歷結果:\n";
arrayRecursivePrint($data);
?>
原始結構:
Array
(
[1] => Array
(
[0] => 11
[1] => 12
[2] => 13
[14] => Array
(
[0] => 141
[1] => 142
)
)
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
遍歷結果:
[0] => 11
[1] => 12
[2] => 13
[0] => 141
[1] => 142
[2] => 2
[3] => 3
[4] => 4
[5] => 5
<?php
/**
* 將多維陣列扁平化為 ['路徑.鍵' => 值]
*/
function arrayFlatten(array $arr, string $prefix = ''): array {
$result = [];
foreach ($arr as $key => $val) {
$newKey = $prefix ? "$prefix.$key" : (string)$key;
if (is_array($val)) {
$result = array_merge($result, arrayFlatten($val, $newKey));
} else {
$result[$newKey] = $val;
}
}
return $result;
}
print_r(arrayFlatten($data));
/*
輸出:
Array
(
[1.0] => 11
[1.1] => 12
[1.2] => 13
[1.14.0] => 141
[1.14.1] => 142
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
*/
?>
<?php
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($data),
RecursiveIteratorIterator::SELF_FIRST // 或 LEAVES_ONLY
);
foreach ($iterator as $key => $val) {
$depth = $iterator->getDepth();
echo str_repeat(' ', $depth) . "[$key] => $val\n";
}
?>
**優點**:內建、記憶體效率佳 (迭代器模式)、支援 `getDepth()`、`hasChildren()`、可搭配 `FilterIterator` 過濾。
| 方案 | 適用場景 | 記憶體 | 速度 |
|---|---|---|---|
| 遞迴函式 | 簡單邏輯、深度 < 100、需自訂處理 | 較高 (呼叫棧) | 快 |
| SPL 迭代器 | 深度未知、大陣列、需過濾/轉換 | 低 (單次遍歷) | 中等 |
| 手動堆疊模擬 | 極深層級、避免棧溢位 | 可控 | 較慢 |
<?php
function arrayIterativeFlatten(array $arr): array {
$stack = [['arr' => $arr, 'prefix' => '']];
$result = [];
while ($stack) {
$frame = array_pop($stack);
foreach ($frame['arr'] as $key => $val) {
$newKey = $frame['prefix'] ? $frame['prefix'] . '.' . $key : (string)$key;
if (is_array($val)) {
$stack[] = ['arr' => $val, 'prefix' => $newKey];
} else {
$result[$newKey] = $val;
}
}
}
return $result;
}
?>