Могу ли я запускать сборку мусора PHP автоматически, если у меня есть круговые ссылки?

Кажется, я вспоминаю способ настройки __destruct для класса таким образом, чтобы гарантировать, что циклические ссылки будут очищены, как только внешний объект выпадет из области видимости. Тем не менее, простой тест, который я построил, кажется, указывает на то, что это не ведет себя так, как я ожидал / надеялся.

Есть ли способ настроить мои классы таким образом, чтобы PHP правильно их очищал, когда внешний объект выпадает из области видимости?

Я не ищу альтернативные способы написания этого кода, я ищу, можно ли это сделать, и если да, то как? Обычно я стараюсь избегать этих типов циркулярных ссылок.

 class Bar { private $foo; public function __construct($foo) { $this->foo = $foo; } public function __destruct() { print "[destroying bar]\n"; unset($this->foo); } } class Foo { private $bar; public function __construct() { $this->bar = new Bar($this); } public function __destruct() { print "[destroying foo]\n"; unset($this->bar); } } function testGarbageCollection() { $foo = new Foo(); } for ( $i = 0; $i < 25; $i++ ) { echo memory_get_usage() . "\n"; testGarbageCollection(); } с class Bar { private $foo; public function __construct($foo) { $this->foo = $foo; } public function __destruct() { print "[destroying bar]\n"; unset($this->foo); } } class Foo { private $bar; public function __construct() { $this->bar = new Bar($this); } public function __destruct() { print "[destroying foo]\n"; unset($this->bar); } } function testGarbageCollection() { $foo = new Foo(); } for ( $i = 0; $i < 25; $i++ ) { echo memory_get_usage() . "\n"; testGarbageCollection(); } с class Bar { private $foo; public function __construct($foo) { $this->foo = $foo; } public function __destruct() { print "[destroying bar]\n"; unset($this->foo); } } class Foo { private $bar; public function __construct() { $this->bar = new Bar($this); } public function __destruct() { print "[destroying foo]\n"; unset($this->bar); } } function testGarbageCollection() { $foo = new Foo(); } for ( $i = 0; $i < 25; $i++ ) { echo memory_get_usage() . "\n"; testGarbageCollection(); } 

Результат выглядит следующим образом:

 60440 61504 62036 62564 63092 63620 [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] 

На что я надеялся:

 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 

ОБНОВИТЬ:

Есть несколько замечательных ответов на этот вопрос, относящихся к PHP> 5.3, но я выбрал ответ, который будет работать с PHP <5.3, поскольку он действительно относится к моему проекту (PHP 5.2.x).