When will __destruct not be called in PHP?
class MyDestructableClass { function __construct() { print "\nIn constructor\n"; $this->name = "MyDestructableClass"; } function __destruct() { print "\nDestroying " . $this->name . "\n"; } } $obj = new MyDestructableClass(); When the above script is in the complex environment, __destruct will not be called when exit , but I cannot play it easily. Has anyone ever noticed this
EDIT
I posted all the material here, it is a symfony test environment, which means you can easily reproduce it if you are familiar with the framework:
require_once dirname(__FILE__).'/../bootstrap/Doctrine.php'; $profiler = new Doctrine_Connection_Profiler(); $conn = Doctrine_Manager::connection(); $conn->setListener($profiler); $t = new lime_test(0, new lime_output_color()); class MyDestructableClass { function __construct() { print "\nIn constructor\n"; $this->name = "MyDestructableClass"; } function __destruct() { print "\nDestroying " . $this->name . "\n"; } } $obj = new MyDestructableClass(); $news = new News(); $news->setUrl('http://test'); $news->setHash('http://test'); $news->setTitle('http://test'); $news->setSummarize('http://test'); $news->setAccountId(1); $news->setCategoryId(1); $news->setThumbnail('http://test'); $news->setCreatedAt(date('Ymd H:i:s',time())); $news->setUpdatedAt(date('Ymd H:i:s',time())); $news->save(); exit(); __destruct will not be called:
- If
exitis called in another destructor - Depending on the PHP version: if
exitis called in the shutdown function registered inregister_shutdown_function - If the code has a fatal error
- If another destructor throws an exception
- If you try to handle the exception in the destructor (PHP> = 5.3.0)
Guess what I can think now
& What Pascal MARTIN said. This is the first step in debugging this.
The lack of output on the screen does not mean that the destructor is not being called: ouptut can be captured using output_buffering (maybe lime it to be able to work on it?), And not echo when the script ends, for example.
For testing purposes, you can try writing the file to your __destruct method instead of just repeating some text.
(Just make sure your application / PHP has the necessary permissions to write to the destination file)
(I already faced situations when I did not see the conclusion made in the destructor, but it was actually called)
As the PHP documentation says:
The destructor will be called even if the script is terminated using
exit(). Callingexit()in the destructor will prevent the rest of the shutdown procedures from being executed.
The __destruct method __destruct also not be called if a script is running in the CLI and receives SIGTERM ( Ctrl + C )
I know I'm a little late to the party, but for people who also want to get __destruct to execute when CTRL + C and / or fatal errors occur, you can try this (below is a test case):
Index.php
<?php // Setup CTRL+C and System kill message handler // The only signal that cannot be caught is the SIGKILL (very hard kill) declare(ticks = 1); // Required else it won't work. pcntl_signal(SIGTERM, 'close'); // System kill (Unhappy Termination) pcntl_signal(SIGINT, 'close'); // CTRL+C (Happy Termination) // Shutdown functions will be executed even on fatal errors register_shutdown_function('close'); function close($signal = null) // only pcntl_signal fills $signal so null is required { // Check if there was an fatal error (else code below isn't needed) $err = error_get_last(); if(is_array($err)) { foreach(array_keys($GLOBALS) as $key) { if(in_array($key, ['_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_REQUEST', '_ENV', 'GLOBALS'])) continue; // This will automatically call __destruct unset($GLOBALS[$key]); } } } // Example class blah { private $id = ''; public function __construct() { $this->id = uniqid(); // note this piece of code, doesn't work on windows! exec('mkdir /tmp/test_'.$this->id); } public function __destruct() { // note this piece of code, doesn't work on windows! exec('rm /tmp/test_'.$this->id.' -R'); } } // Test $a = new blah(); $b = new blah(); $c = new blah(); $d = new blah(); $e = new blah(); $f = new blah(); $g = new blah(); $h = new blah(); $i = new blah(); $j = new blah(); $k = new blah(); $l = new blah(); $m = new blah(); $n = new blah(); $o = new blah(); $p = new blah(); $q = new blah(); $r = new blah(); $s = new blah(); $t = new blah(); $u = new blah(); $v = new blah(); $w = new blah(); $x = new blah(); $y = new blah(); $z = new blah(); // The script that causes an fatal error require_once(__DIR__.'/test.php'); test.php
<?php // this will create a parse (E_PARSE) error. asdsaddsaadsasd Note: calling exceptions for an exception or an exception in destructors or a shutdown function will cause the script to terminate immediately.
Not familiar with the Doctrine, but check one point: check for possible exceptions in __construct () / __ destruct (), they can lead to fatal errors.