遞迴 是函式直接或間接呼叫自身的技術,適合解決「問題可分解為相同性質的較小子問題」的場景:階乘、費波那契、樹狀結構遍歷、目錄遞迴掃描等。
<?php
function abc($n) {
if ($n > 2) { // 遞迴條件
abc(--$n); // 遞迴呼叫 (前置遞減)
}
echo '$n=' . $n . "<br />"; // 每層返回時輸出
}
abc(4);
?>
abc(4) ├─ n=4 > 2 → abc(--n) → abc(3) │ ├─ n=3 > 2 → abc(--n) → abc(2) │ │ ├─ n=2 ≯ 2 → 輸出 $n=2 → 返回 │ │ └─ 返回上層 → 輸出 $n=2 → 返回 │ └─ 返回上層 → 輸出 $n=3 → 返回 └─ 返回主程式 → 結束 輸出順序: $n=2 $n=2 $n=3
--$n (前置遞減) 在呼叫前修改變數值,導致同一層級的兩次輸出皆為 2。abc($n - 1) (不修改原變數),輸出將為 2, 3, 4。xdebug.max_nesting_level (預設 256) 與記憶體限制;深度遞迴請改用迴圈或增加限制。<?php
function factorial($n) {
if ($n <= 1) return 1; // 基礎案例
return $n * factorial($n - 1); // 遞迴步驟
}
echo factorial(5); // 120
?>
<?php
function scanDir($path) {
$items = scandir($path);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$full = $path . DIRECTORY_SEPARATOR . $item;
if (is_dir($full)) {
echo "[DIR] $full\n";
scanDir($full); // 遞迴進入子目錄
} else {
echo "[FILE] $full\n";
}
}
}
scanDir(__DIR__);
?>
| 維度 | 遞迴 | 迴圈 |
|---|---|---|
| 程式碼簡潔度 | 高 (樹狀/分形問題) | 低 (需自維護堆疊) |
| 記憶體消耗 | O(深度) 呼叫堆疊 | O(1) 常數空間 |
| 執行速度 | 較慢 (函式呼叫開銷) | 較快 |
| 除錯難度 | 較高 (堆疊追蹤) | 較低 |
| 適用場景 | 樹/圖遍歷、分治演算法、語法解析 | 線性處理、已知迴圈次數 |
PHP 不支援 尾端遞迴優化,所有遞迴皆佔用堆疊幀。深度遞迴 (> 1000 層) 必須改寫為迴圈或使用 Generator / 手動堆疊模擬。
debug_backtrace() 或 xdebug_var_dump() 觀察呼叫堆疊。ini_set('xdebug.max_nesting_level', 500) 臨時放寬限制。declare(ticks=1) + register_tick_function 監控遞迴深度。理解遞迴機制與 PHP 實作限制,能讓您在適合場景 (樹狀結構、分治演算法) 優雅解決問題,並在不適合場景果斷選擇迴圈替代。