php中__destruct與register_shutdown_function執(zhí)行的先后順序問題
來源:易賢網(wǎng) 閱讀:951 次 日期:2014-11-13 14:46:46
溫馨提示:易賢網(wǎng)小編為您整理了“php中__destruct與register_shutdown_function執(zhí)行的先后順序問題”,方便廣大網(wǎng)友查閱!

根據(jù)php手冊的解析。

__destruct是

析構(gòu)函數(shù)會在到某個對象的所有引用都被刪除或者當(dāng)對象被顯式銷毀時執(zhí)行。

而register_shutdown_function是

Registers a callback to be executed after script execution finishes or exit() is called. 注冊一個回調(diào)函數(shù),此函數(shù)在腳本運行完畢或調(diào)用exit()時執(zhí)行。

從字面上理解,__destruct是對象層面的,而register_shutdown_function是整個腳本層面的,理應(yīng)register_shutdown_function的級別更高,其所注冊的函數(shù)也應(yīng)最后執(zhí)行。為證實我們的猜測,我們寫一段腳本:

代碼如下:

register_shutdown_function(function(){echo 'global';});

class A {

public function __construct(){

}

public function __destruct()

{

echo __class__,'::',__function__,'<br/>';

}

}

new A;

執(zhí)行結(jié)果:

代碼如下:

A::__destruct

global

完全證實了我們的猜測,它按照對象->腳本的順序被執(zhí)行了。

但如果我們在對象中注冊了register_shutdown_function呢?它還是一樣的順序嗎?!

代碼如下:

class A {

public function __construct(){

register_shutdown_function(function(){echo 'local', '<br/>';});

}

public function __destruct()

{

echo __class__,'::',__function__,'<br/>';

}

}

new A;

結(jié)果:

復(fù)制代碼 代碼如下:

local

A::__destruct

可以看到register_shutdown_function先被調(diào)用了,最后才是執(zhí)行對象的__destruct。這表明register_shutdown_function注冊的函數(shù)被當(dāng)作類中的一個方法?!不得而知,這可能需要查看php源代碼才能解析了。

我們可以擴(kuò)大范圍查看情況:

代碼如下:

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函數(shù),在類AB中又各注冊了一個,而且類中分別還有析構(gòu)方法。最后運行結(jié)果會怎樣呢?

代碼如下:

global

B::op

A::op

A::__destruct

B::__destruct

結(jié)果完全顛覆了我們的想像,register_shutdown_function函數(shù)無論在類中注冊還是在全局注冊,它都是先被執(zhí)行,類中執(zhí)行的順序就是它們被注冊的先后順序。如果我們再仔細(xì)研究,全局的register_shutdown_function函數(shù)無論放在前面還是后面都是這個結(jié)果,事情似乎有了結(jié)果,那就是register_shutdown_function比__destruct先執(zhí)行,全局的register_shutdown_function函數(shù)又先于類中注冊的register_shutdown_function先執(zhí)行。

且慢,我無法接受這個結(jié)果,按照這樣的結(jié)論,難道說腳本已經(jīng)結(jié)束后還可以再執(zhí)行__destruct?!因此,我還要繼續(xù)驗證這個結(jié)論---去掉類中注冊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

結(jié)果令人茫然,A、B兩個類的析構(gòu)函數(shù)執(zhí)行順序無可質(zhì)疑,因為B中調(diào)用了A,類A肯定比B先銷毀,但全局的register_shutdown_function函數(shù)又怎么夾在它們中間被執(zhí)行?!費解。

按照手冊的解析,析構(gòu)函數(shù)也可在調(diào)用exit時執(zhí)行。

析構(gòu)函數(shù)即使在使用 exit()終止腳本運行時也會被調(diào)用。在析構(gòu)函數(shù)中調(diào)用 exit() 將會中止其余關(guān)閉操作的運行。

如果在函數(shù)中調(diào)用exit,它們又如何被調(diào)用的呢?

代碼如下:

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;

輸出:

代碼如下:

global

B::op

A::op

B::__destruct

A::__destruct

這個順序與上述第三個例子相似,不同的且令人不可思議的是B類的析構(gòu)函數(shù)先于類A執(zhí)行,難道銷毀B后類A的所有引用才被全部銷毀?!不得而知。

結(jié)論:

1、盡量不要在腳本中將register_shutdown_function與__destruct混搭使用,它們的行為完全不可預(yù)測。

1、因為對象在相互引用,因此我們無法測知對象幾時被銷毀,當(dāng)需要按順序輸出內(nèi)容時,不應(yīng)把內(nèi)容放在析構(gòu)函數(shù)__destruct里;

2、盡量不要在類中注冊register_shutdown_function,因為它的順序難以預(yù)測(只有調(diào)用這個對象時才會注冊函數(shù)),而且__destruct完全可以代替register_shutdown_function;

3、如果需要在腳本退出時執(zhí)行相關(guān)動作,最好在腳本開始時注冊register_shutdown_function,并把所有動作放在一個函數(shù)里。

更多信息請查看IT技術(shù)專欄

更多信息請查看網(wǎng)絡(luò)編程
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機(jī)站點

版權(quán)所有:易賢網(wǎng)