遞歸函數是程式設計中常見且強大的技術,其核心特徵是函數在內部呼叫自身。然而,若缺乏終止條件,將陷入無限遞歸導致堆疊溢位。本文將深入探討 PHP 中實現遞歸的三種基本模式——引用參數、全域變數與靜態變數,並透過實例剖析其運作機制與適用場景。
引用的本質是讓兩個不同名稱的變數指向同一塊記憶體位址。在遞歸場景中,將結果陣列以引用方式傳遞,可構建各層遞歸間的資料共享橋樑。
function test($a = 0, &$result = array()) {
$a++;
if ($a < 10) {
$result[] = $a;
test($a, $result);
}
echo $a;
return $result;
}
執行流程解析:
原因在於 echo $a 位於遞歸呼叫之後,必須待最深層返回後,逐層向上執行輸出。
global 關鍵字在函數內宣告變數,實際建立的是外部同名變數的引用。雖作用域仍限於函數內,但修改值會影響外部原變數。
function test($a = 0, $result = array()) {
global $result;
$a++;
if ($a < 10) {
$result[] = $a;
test($a, $result);
}
return $result;
}
此方式理解門檻較低,但全域變數易造成命名衝突與副作用,實務上建議謹慎使用。
static 變數僅在首次呼叫函數時初始化,後續呼叫保留上次值,不再重複初始化。此特性天然適合作為遞歸層間的狀態保持器。
function test($a = 0) {
static $result = array();
$a++;
if ($a < 10) {
$result[] = $a;
test($a);
}
return $result;
}
優點:函數簽名乾淨,無需額外參數;缺點:靜態變數生命週期贏整個腳本執行期間,若同一函數被多處呼叫會互相干擾,需注意重置機制。
遞歸是處理樹狀結構(如無限級分類)的利器。以下示範如何從扁平陣列構建層級結構:
$area = [
['id'=>1, 'area'=>'北京', 'pid'=>0],
['id'=>11,'area'=>'朝陽區','pid'=>1],
['id'=>113,'area'=>'亞運村','pid'=>11],
// ...更多資料
];
function buildTree($arr, $pid = 0, $level = 0) {
static $list = [];
foreach ($arr as $v) {
if ($v['pid'] == $pid) {
echo str_repeat(' ', $level) . $v['area'] . '
';
$list[] = $v;
buildTree($arr, $v['id'], $level + 1);
}
}
return $list;
}
| 方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 引用參數 | 明確、可控、無副作用 | 參數列較長 | 通用遞歸、需多狀態傳遞 |
| 全域變數 | 簡單直觀 | 污染全域命名空間、難維護 | 簡單腳本、快速原型 |
| 靜態變數 | 介面乾淨、狀態自動保持 | 函數非可重入、並發不安全 | 單執行緒、單一呼叫鏈 |
深入理解變數引用、作用域與生命週期,是掌握遞歸精髓的關鍵。實務開發中,建議優先考慮引用參數或封裝為類的靜態屬性,以獲得更好的可維護性與擴展性。