今天遇到了,在 PHP 里类循环引用时,会导致 __destruct() 不触发的问题,先上问题代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <?php class Proxy { private $object ; public function __construct( $object ) { $this ->object = $object ; } public function __destruct() { var_dump( '__destruct:Proxy' ); } } class Test { private $proxy ; public function __construct() { $this ->proxy = new Proxy( $this ); } public function __destruct() { var_dump( '__destruct:Test' ); } } $test = new Test; unset( $test ); echo 'no __destruct, wait 3s' , PHP_EOL; sleep(3); echo '__destruct now:' , PHP_EOL; |
如上代码,运行unset($test)时,不会触发__destruct(),因为有了循环引用。再看下面的解决方法1的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php class Proxy { private $object ; public function __construct( $object ) { $this ->object = $object ; } public function __destruct() { var_dump( '__destruct:Proxy' ); } } class Test { private $proxy ; public function __construct() { $this ->proxy = new Proxy( $this ); } public function __destruct() { var_dump( '__destruct:Test' ); } public function close() { $this ->proxy = null; } } $test = new Test; $test ->close(); echo '__destruct now:' , PHP_EOL; unset( $test ); sleep(3); echo 'no operation' , PHP_EOL; |
上面的代码,在unset之前,将Test类中的proxy设为null,然后再unset,就可以触发__destruct()了。
当然,你也可以手动gc(解决方法2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <?php class Proxy { private $object ; public function __construct( $object ) { $this ->object = $object ; } public function __destruct() { var_dump( '__destruct:Proxy' ); } } class Test { private $proxy ; public function __construct() { $this ->proxy = new Proxy( $this ); } public function __destruct() { var_dump( '__destruct:Test' ); } } $test = new Test; unset( $test ); echo '__destruct now:' , PHP_EOL; gc_collect_cycles(); sleep(3); echo 'no operation' , PHP_EOL; |
自己记录一下,希望也能帮到有缘人~
友情提示:垃圾评论一律封号...