亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

【In PHP】析構(gòu)、作用域與引用

fai1017 / 1430人閱讀

摘要:在編寫一段析構(gòu)方法的研究代碼中,我遇到了交叉知識(shí)點(diǎn)導(dǎo)致的錯(cuò)誤在不同作用域,析構(gòu)方法與引用次數(shù)導(dǎo)致了不一樣的結(jié)果。前提本文假裝你已經(jīng)明白什么是析構(gòu)方法作用域及引用次數(shù)。當(dāng)析構(gòu)函數(shù)的調(diào)用鉤子去檢測(cè)引用數(shù)時(shí),全局的實(shí)例自然無法觸發(fā)這個(gè)事件。

在編寫一段析構(gòu)方法的研究代碼中,我遇到了交叉知識(shí)點(diǎn)導(dǎo)致的錯(cuò)誤——在不同作用域,析構(gòu)方法與引用次數(shù)導(dǎo)致了不一樣的結(jié)果。
前提

本文假裝你已經(jīng)明白什么是析構(gòu)方法、作用域及引用次數(shù)。關(guān)于后者,引用次數(shù)是 PHP 垃圾收集中的重要機(jī)制,它很大程度上,幫助 PHP 在程序運(yùn)行時(shí)清理內(nèi)存垃圾(參考:引用計(jì)數(shù)基礎(chǔ) - PHPDoc)。

正文 有誤的測(cè)試

來看這段代碼:

class A {
    public $var = [];

    public function __construct()
    {
        echo "__construct: " . spl_object_hash($this) . "
";
    }

    public function __destruct()
    {
        echo "__destruct: " . spl_object_hash($this);
    }

    public function test()
    {
        throw new Exception("Hello");
    }
}

$test = new A();
$test->test();

我的本意是“在拋出不捕獲的異常時(shí),析構(gòu)方法是否正常執(zhí)行”。結(jié)果是沒有執(zhí)行,OK,很穩(wěn):

__construct: 0000000045f0af9e00000000494744b0
Fatal error: Uncaught Exception: Hello in...

當(dāng)我們以為事情就此結(jié)束,后續(xù)往往會(huì)接踵而來。

翻車的代碼

在公司前輩指出“你這段代碼有問題,犯了作用域的錯(cuò)誤”之后,我是當(dāng)場(chǎng)宕機(jī)的。


啥,作用域?析構(gòu)方法?我是不是聽錯(cuò)了,那玩意不是變量的概念么。

經(jīng)過我的追問,前輩告訴我:你把執(zhí)行代碼放到函數(shù)里試試。

避免文章過長(zhǎng),直接上差異部分的代碼,如下:

class A {
    // 與之前一致
}

function test()
{
    $test = new A();
    $test->test();
}

test();

結(jié)果如下:

__construct: 000000004b11d811000000006f9a75c7
__destruct: 000000004b11d811000000006f9a75c7
Fatal error: Uncaught Exception: Hello in...

心態(tài)如下:


說好的不執(zhí)行呢?真是令人絕望。

當(dāng)場(chǎng)打臉,只好去琢磨“析構(gòu)方法的作用域”是個(gè)啥。搜索結(jié)果里看到了這樣的話:

析構(gòu)函數(shù)會(huì)在到某個(gè)對(duì)象的所有引用都被刪除或者當(dāng)對(duì)象被顯式銷毀時(shí)執(zhí)行。來源:構(gòu)造與析構(gòu)函數(shù) - PHPDoc

讓我們推理一下:

函數(shù)結(jié)束后,該函數(shù)級(jí)別的作用域就結(jié)束了,而此時(shí)腳本還未結(jié)束。沒有任何引用的對(duì)象實(shí)例,自然可以執(zhí)行析構(gòu)方法;

全局作用域則不一樣,所以導(dǎo)致了對(duì)象在全局作用域結(jié)束后,沒機(jī)會(huì)調(diào)用析構(gòu)方法。

結(jié)果似乎明朗了。

深入

當(dāng)然,淺嘗輒止可對(duì)不起我的好奇心。既然要搞明白這個(gè)問題,那就問一問核心問題:

證實(shí):函數(shù)級(jí)別的作用域結(jié)束與對(duì)象執(zhí)行析構(gòu)方法,是否有必然聯(lián)系?

新問題:調(diào)用析構(gòu)方法與結(jié)束變量,誰先誰后?


相信在理清上述兩個(gè)問題的答案后,這個(gè)文章也就沒有存在的意義了,笑~

問題一
函數(shù)級(jí)別的作用域結(jié)束與對(duì)象執(zhí)行析構(gòu)方法,是否有必然聯(lián)系?

很簡(jiǎn)單,咱們讓對(duì)象與函數(shù)的作用域脫鉤,就可以逆向地證實(shí)這一點(diǎn):

class A {
    // 與之前一致
}
$i = 123;

function test(&$i) // 通過引用機(jī)制,給函數(shù)的作用域增加污染變量
{
    $test = new A();
    $i = $test; // 將對(duì)象實(shí)例的引用擴(kuò)展到全局作用域
    $test->test();
}

test($i);

結(jié)果如下:

__construct: 0000000042a054c3000000001f53236f
Fatal error: Uncaught Exception: Hello in...

果然,當(dāng)引用計(jì)數(shù)不為 0 時(shí),析構(gòu)函數(shù)就不會(huì)被調(diào)用,賊穩(wěn)~

問題二
新問題:調(diào)用析構(gòu)方法與結(jié)束變量,誰先誰后?

這個(gè)問題就有點(diǎn)意思了,熟悉程序的朋友又應(yīng)該明白,遇到這種“X的某個(gè)機(jī)制是什么時(shí)候觸發(fā)的”,就應(yīng)該去看X的生命周期,X 泛指一切。

在經(jīng)過一番查找,我從《PHP7內(nèi)核剖析》中找到了 PHP 的生命周期,注意我標(biāo)紅圈的兩個(gè)地方:

清理全局變量與析構(gòu)方法的調(diào)用,我們就找到了。

但此時(shí)困惑了我的問題就變成了:普通變量到底什么時(shí)候銷毀?

我翻遍了 PHP 的生命周期、網(wǎng)絡(luò)上的文章,也沒找到想要的答案。大家都在聊全局變量的銷毀事件,難道全局的普通變量是弱勢(shì)群體嗎?

直到我看到 PHP 手冊(cè)上的范例:

// 使用 global

$a = 1;
$b = 2;

function Sum()
{
    global $a, $b;

    $b = $a + $b;
}

Sum();
echo $b;

原來 全局范圍的普通變量 = 全局變量,這結(jié)論真是令我頭禿。

最終總結(jié)一下:

當(dāng)實(shí)例的引用為 0 時(shí),會(huì)步入銷毀階段,此時(shí),析構(gòu)函數(shù)才會(huì)啟用;

當(dāng)對(duì)象的實(shí)例位于全局作用域,該變量會(huì)在 全局變量銷毀 事件中銷毀,在此之前,全局變量的引用數(shù)至少為 1;

析構(gòu)函數(shù)的調(diào)用 發(fā)生在 全局變量銷毀 之前。

當(dāng)析構(gòu)函數(shù)的調(diào)用鉤子去檢測(cè)“引用數(shù)”時(shí),全局的實(shí)例自然無法觸發(fā)這個(gè)事件。

至于為什么會(huì)犯這樣的錯(cuò)誤,原因也有兩個(gè):

對(duì) PHP 的生命周期認(rèn)知模糊不清;

不清楚 PHP 的全局變量如何定義。

為什么會(huì)犯這兩個(gè)錯(cuò)誤,自然也有理由,但無論什么理由,都解決不了在面對(duì)知識(shí)點(diǎn)交叉時(shí),因?yàn)橹R(shí)盲點(diǎn)所犯下的錯(cuò)。下次學(xué)東西,還是跟著官方文檔學(xué)習(xí)吧。


圖片出處源自網(wǎng)絡(luò)或水印,侵刪。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/29766.html

相關(guān)文章

  • PHP面試之面向?qū)ο螅?)

    摘要:二面向?qū)ο笥惺裁刺卣髅嫦驅(qū)ο蟮闹饕卣饔谐橄罄^承封裝和多態(tài)。析構(gòu)函數(shù)析構(gòu)函數(shù)是在引入的,它的作用與調(diào)用時(shí)機(jī)和構(gòu)造函數(shù)剛好相反,它在對(duì)象被銷毀時(shí)自動(dòng)執(zhí)行。 PHP面試專欄正式起更,每周一、三、五更新,提供最好最優(yōu)質(zhì)的PHP面試內(nèi)容。PHP中面向?qū)ο蟪?嫉闹R(shí)點(diǎn)有以下7點(diǎn),我將會(huì)從以下幾點(diǎn)進(jìn)行詳細(xì)介紹說明,幫助你更好的應(yīng)對(duì)PHP面試常考的面向?qū)ο笙嚓P(guān)的知識(shí)點(diǎn)和考題。整個(gè)面向?qū)ο笪恼碌慕Y(jié)構(gòu)涉...

    phodal 評(píng)論0 收藏0
  • 重讀PHP手冊(cè)筆記系列(二)

    摘要:通過注冊(cè)自動(dòng)加載器,腳本引擎在出錯(cuò)失敗前有了最后一個(gè)機(jī)會(huì)加載所需的類構(gòu)造函數(shù)和析構(gòu)函數(shù)構(gòu)造函數(shù)允行開發(fā)者在一個(gè)類中定義一個(gè)方法作為構(gòu)造函數(shù)。析構(gòu)函數(shù)會(huì)在到某個(gè)對(duì)象的所有引用都被刪除或者當(dāng)對(duì)象被顯式銷毀時(shí)執(zhí)行抽象類支持抽象類和抽象方法。 語言參考 1. 類型 1.1 簡(jiǎn)介 showImg(https://segmentfault.com/img/bVbqlNJ?w=531&h=379);...

    馬龍駒 評(píng)論0 收藏0
  • php易錯(cuò)筆記-類與對(duì)象,命名空間

    摘要:類與對(duì)象基本概念如果在之后跟著的是一個(gè)包含有類名的字符串,則該類的一個(gè)實(shí)例被創(chuàng)建。如果該類屬于一個(gè)名字空間,則必須使用其完整名稱。如果一個(gè)類被聲明為,則不能被繼承。命名空間通過關(guān)鍵字來聲明。 類與對(duì)象 基本概念 new:如果在 new 之后跟著的是一個(gè)包含有類名的字符串,則該類的一個(gè)實(shí)例被創(chuàng)建。如果該類屬于一個(gè)名字空間,則必須使用其完整名稱。 Example #3 創(chuàng)建一個(gè)實(shí)例 ...

    MartinHan 評(píng)論0 收藏0
  • PHP面試常考內(nèi)容之面向?qū)ο螅?)

    摘要:繼上一篇面試??純?nèi)容之面向?qū)ο蟀l(fā)表后,今天更新,需要的可以直接點(diǎn)擊文字進(jìn)行跳轉(zhuǎn)獲取。析構(gòu)函數(shù),當(dāng)對(duì)象被銷毀時(shí)調(diào)用。 PHP面試專欄正式起更,每周一、三、五更新,提供最好最優(yōu)質(zhì)的PHP面試內(nèi)容。繼上一篇PHP面試??純?nèi)容之面向?qū)ο螅?)發(fā)表后,今天更新(2),需要(1)的可以直接點(diǎn)擊文字進(jìn)行跳轉(zhuǎn)獲取。整個(gè)面向?qū)ο笪恼碌慕Y(jié)構(gòu)涉及的內(nèi)容模塊有: 一、面向?qū)ο笈c面向過程有什么區(qū)別?二、面向?qū)?..

    Barry_Ng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<