Кажется, я вспоминаю способ настройки __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).