<?php
function test($i) {
$i -= 4;
if ($i < 3) {
return $i;
} else {
test($i); // 錯誤:遞歸調用結果未返回
}
}
echo test(30); // 輸出空白,無返回值
?>
test(30) → 進入 else 分支test(26) → 同樣進入 elsetest(2) 滿足 $i < 3test(2) 執行 return 2,返回給上一層 test(6) 的呼叫處test(6) 的 else 區塊 沒有接收返回值,也沒有 return,函數隱式返回 nullnull,最終 test(30) 也是 null核心規則:PHP 函數若無 return 語句,或執行路徑未遇到 return,預設返回 null。遞歸時每一層都必須顯式返回下一層的結果。
<?php
function test($i) {
$i -= 4;
if ($i < 3) {
return $i;
} else {
return test($i); // 關鍵:加上 return
}
}
echo test(30); // 輸出 2
?>
雖然加上 return 修正了邏輯,但 PHP 不支援尾調用優化(Tail Call Optimization)。深度遞歸(> 1000 層)會導致 Stack Overflow。
<?php
function testIterative($i) {
while ($i >= 3) {
$i -= 4;
}
return $i;
}
echo testIterative(30); // 2,無棧溢位風險
?>
| 場景 | 建議 | 理由 |
|---|---|---|
| 樹形結構遍歷(分類、評論、目錄) | 遞歸 | 代碼簡潔,深度通常可控(< 100) |
| 數學遞推(費波那契、階乘) | 迭代 + 緩存 | 遞歸重複計算指數級,記憶體風險大 |
| 深度未知的鏈表/圖遍歷 | 迭代 + 顯式堆疊 | 避免棧溢位,可控制記憶體 |
| 模板引擎渲染、AST 遍歷 | 遞歸 | 結構天然遞歸,深度受模板複雜度限制 |
<?php
function testDebug($i, $depth = 0) {
$indent = str_repeat(' ', $depth);
echo "$indent> test($i)\n";
$i -= 4;
if ($i < 3) {
echo "$indent< return $i\n";
return $i;
} else {
$ret = testDebug($i, $depth + 1);
echo "$indent< return $ret\n";
return $ret;
}
}
testDebug(30);
?>
輸出清晰展示每層進入與返回,極利於理解遞歸流程。