According to the PHP manual.
_ Destruct is
The Destructor is executed when all references to an object are deleted or when the object is explicitly destroyed.
While register_shutdown_function is
Registerscallback
To be executed after script execution finishes or exit () is called. registers a callback function that is executed when the script is run or exit () is called.
Literally speaking, __destruct is at the object level, while register_shutdown_function is at the script level. It is supposed that register_shutdown_function has a higher level and the registered function should be executed at the end. To prove our guesses, we have written a script:
register_shutdown_function(function(){echo ‘global‘;}); class A { public function __construct(){ } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } } new A;
Execution result:
A: :__ destruct
Global
It fully proves our conjecture that it is executed in the order of Object-> script.
But what if we have registered register_shutdown_function in the object? Is it in the same order ?!
class A { public function __construct(){ register_shutdown_function(function(){echo ‘local‘, ‘<br/>‘;}); } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } } new A;
Result:
Local
A: :__ destruct
We can see that register_shutdown_function is called first, and finally the _ destruct of the execution object. This indicates that the function registered by register_shutdown_function is treated as a method in the class ?! Unknown, this may need to view the PHP source code for parsing.
We can expand the scope to view the situation:
register_shutdown_function(function(){echo ‘global‘, ‘<br/>‘;}); class A { public function __construct(){ register_shutdown_function(array($this, ‘op‘));
} public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } public function op() { echo __class__,‘::‘,__function__,‘<br/>‘; } } class B { public function __construct() { register_shutdown_function(array($this, ‘op‘)); $obj = new A; } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } public function op() { echo __class__,‘::‘,__function__,‘<br/>‘; } } $b = new B;
We register a register_shutdown_function globally, register another function in class AB, and the class also has the destructor. What is the final running result?
Global
B: op
A: op
A: :__ destruct
B: :__ destruct
The result completely subverts our imagination. The register_shutdown_function is first executed no matter whether it is registered in the class or globally, and the execution sequence in the class is the order in which they are registered. If we study the global register_shutdown_function both in front and in the back, it seems that the result is returned, that is, register_shutdown_function is executed first than _ destruct, the global register_shutdown_function is executed before the register_shutdown_function registered in the class.
I cannot accept this result. According to this conclusion, it is hard to say that the script can be executed again after it is completed _ destruct ?! Therefore, I will continue to verify this conclusion-remove the Registry register_shutdown_function in the class and keep the global register_shutdown_function:
class A { public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } } class B { public function __construct() { $obj = new A; } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } } register_shutdown_function(function(){echo ‘global‘, ‘<br/>‘;});
Output:
A: :__ destruct
Global
B: :__ destruct
The result is confusing. The execution sequence of destructor A and B is unquestionable. Because Class A is definitely destroyed before class B when class A is called in Class B, but how can the global register_shutdown_function be executed in the middle of them ?! Confusing.
According to the manual parsing, The Destructor can also be executed when exit is called.
The Destructor will be called even when the exit () Termination script is used. Calling exit () in the Destructor will stop other close operations.
How can exit be called in a function?
class A { public function __construct(){ register_shutdown_function(array($this, ‘op‘)); exit; } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } public function op() { echo __class__,‘::‘,__function__,‘<br/>‘; } } class B { public function __construct() { register_shutdown_function(array($this, ‘op‘)); $obj = new A; } public function __destruct() { echo __class__,‘::‘,__function__,‘<br/>‘; } public function op() { echo __class__,‘::‘,__function__,‘<br/>‘; } } register_shutdown_function(function(){echo ‘global‘, ‘<br/>‘;}); $b = new B;
Output:
Global
B: op
A: op
B: :__ destruct
A: :__ destruct
This order is similar to the third example above. What is different and incredible is that Class B destructor are executed before Class, will all references to Class A be destroyed after Class B is destroyed ?! Unknown.
Conclusion:
- 1. Try not to mix register_shutdown_function and _ destruct in the script. Their behavior is completely unpredictable.
- 1. Because the objects are being referenced by each other, we cannot determine when the objects will be destroyed. When the content needs to be output in order, the content should not be placed in the Destructor _ destruct;
- 2. Try not to register register_shutdown_function in the class, because its order is difficult to predict (the function is registered only when this object is called), and _ destruct can replace register_shutdown_function;
- 3. If you need to execute relevant actions when the script exits, it is best to register register_shutdown_function at the beginning of the script and put all the actions in one function.
Please let us know.
_ Destruct and register_shutdown_function execution sequence