在 PHP 開發中,當物件之間形成循環引用(即物件 A 引用物件 B,而物件 B 又引用物件 A)時,會導致記憶體洩漏。這是一個長期存在的問題,特別是在早期 PHP 版本中尤為明顯。雖然現代 PHP(5.3 及以上)已修復此問題,但理解其原理對於編寫高效能代碼仍有重要價值。
以下代碼示範了典型的循環引用場景:
<?php
class Foo {
function __construct() {
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo) {
$this->foo = $foo;
}
}
for ($i = 0; $i < 100; $i++) {
$obj = new Foo();
unset($obj);
echo memory_get_usage() . "\n";
}
?>
執行後會發現,儘管每次迴圈都 unset($obj),記憶體使用量仍持續增長,說明物件未被正確回收。
在 PHP 5.3 修復前,開發者常通過在建構函式中手動釋放引用來繞過此問題:
<?php
class Foo {
function __construct() {
$this->bar = new Bar($this);
}
function __destruct() {
unset($this->bar);
}
}
class Bar {
function __construct($foo) {
$this->foo = $foo;
}
}
for ($i = 0; $i < 100; $i++) {
$obj = new Foo();
$obj->__destruct();
unset($obj);
echo memory_get_usage() . "\n";
}
?>
雖然有效,但這種寫法較為醜陋,且增加了維護負擔。
好消息是 PHP 5.3 的 CVS 版本已修復此 Bug。升級至 PHP 5.3 或更高版本後,垃圾回收機制能正確處理循環引用,無需手動干預。
memory_get_usage() 監控記憶體狀態__destruct 明確斷開引用作為防禦性編程理解此機制有助於編寫更健壯的 PHP 應用,特別是在長時間運行的 CLI 腳本或高併發服務中。