根據php手冊的解析。
__destruct是
析構函數會在到某個對象的所有引用都被刪除或者當對象被顯式銷毀時執行。
而register_shutdown_function是
Registers a callback to be executed after script execution finishes or exit() is called. 注冊一個回調函數,此函數在腳本運行完畢或調用exit()時執行。
從字面上理解,__destruct是對象層面的,而register_shutdown_function是整個腳本層面的,理應register_shutdown_function的級別更高,其所注冊的函數也應最後執行。為證實我們的猜測,我們寫一段腳本:
代碼如下:
register_shutdown_function(function(){echo 'global';});
class A {
public function __construct(){
}
public function __destruct()
{
echo __class__,'::',__function__,'<br/>';
}
}
new A;
執行結果:
代碼如下:
A::__destruct
global
完全證實了我們的猜測,它按照對象->腳本的順序被執行了。
但如果我們在對象中注冊了register_shutdown_function呢?它還是一樣的順序嗎?!
代碼如下:
class A {
public function __construct(){
register_shutdown_function(function(){echo 'local', '<br/>';});
}
public function __destruct()
{
echo __class__,'::',__function__,'<br/>';
}
}
new A;
結果:
復制代碼 代碼如下:
local
A::__destruct
可以看到register_shutdown_function先被調用了,最後才是執行對象的__destruct。這表明register_shutdown_function注冊的函數被當作類中的一個方法?!不得而知,這可能需要查看php源代碼才能解析了。
我們可以擴大范圍查看情況:
代碼如下:
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;
我們在全局注冊一個register_shutdown_function函數,在類AB中又各注冊了一個,而且類中分別還有析構方法。最後運行結果會怎樣呢?
代碼如下:
global
B::op
A::op
A::__destruct
B::__destruct
結果完全顛覆了我們的想像,register_shutdown_function函數無論在類中注冊還是在全局注冊,它都是先被執行,類中執行的順序就是它們被注冊的先後順序。如果我們再仔細研究,全局的register_shutdown_function函數無論放在前面還是後面都是這個結果,事情似乎有了結果,那就是register_shutdown_function比__destruct先執行,全局的register_shutdown_function函數又先於類中注冊的register_shutdown_function先執行。
且慢,我無法接受這個結果,按照這樣的結論,難道說腳本已經結束後還可以再執行__destruct?!因此,我還要繼續驗證這個結論---去掉類中注冊register_shutdown_function,而保留全局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/>';});
輸出:
代碼如下:
A::__destruct
global
B::__destruct
結果令人茫然,A、B兩個類的析構函數執行順序無可質疑,因為B中調用了A,類A肯定比B先銷毀,但全局的register_shutdown_function函數又怎麼夾在它們中間被執行?!費解。
按照手冊的解析,析構函數也可在調用exit時執行。
析構函數即使在使用 exit()終止腳本運行時也會被調用。在析構函數中調用 exit() 將會中止其余關閉操作的運行。
如果在函數中調用exit,它們又如何被調用的呢?
代碼如下:
class A {
public function __construct(){
register_shutdown_function(array($this, 'op'));
exit;
}
public function __destruct()
{
echo __class__,'::',__function__,'<br/>';
}
public function op()
{
&