PHP7內(nèi)核之Reference詳解
以下是【金聰采編】分享的內(nèi)容全文:
問題
上一章說過引用(REFERENCE)在PHP5的時(shí)候是一個(gè)標(biāo)志位, 而在PHP7以后我們把它變成了一種新的類型:IS_REFERNCE. 然而引用是一種很常見的應(yīng)用, 所以這個(gè)變化帶來了很多的變化, 也給我們?cè)谧鯬HP7開發(fā)的時(shí)候, 因?yàn)橛械臅r(shí)候疏忽忘了處理這個(gè)類型, 而帶來不少的bug.
最簡(jiǎn)單的情況, 就是在處理各種類型的時(shí)候, 從此以后我們要多考慮這種新的類型, 比如在PHP7中, 這樣的代碼形式就變得很常見了:
try_again:swtich (Z_TYPE_P(zv)) { case IS_TRING: break; case IS_ARRAY: break; ... case IS_REFERENCE: zv = Z_REFVAL_P(zv); //解引用 goto try_again; break;}如果大家自己寫的擴(kuò)展, 如果忘了考慮這種新的類型, 那么就會(huì)導(dǎo)致問題.
為什么?
那么既然這種新類型會(huì)帶來這么多問題, 那么當(dāng)時(shí)為什么要用把引用變成一種類型呢? 為什么不還是使用一個(gè)標(biāo)志位呢?
一句話來說, 就是我們不得不這么做. -_#
前面說到, Hashtable直接存儲(chǔ)的是zval, 這樣在符號(hào)表中, 倆個(gè)zval如何共用一個(gè)數(shù)值呢? 對(duì)于字符串等復(fù)雜類型來說還好, 我們貌似可以在zend_refcounted結(jié)構(gòu)中加入一個(gè)標(biāo)志位來表明是引用來解決, 然而這個(gè)也會(huì)遇到Change On Write帶來的復(fù)制, 但是我們知道在PHP7中, 一些類型是直接存儲(chǔ)在zval中的, 比如IS_LONG, 但是引用類型是需要引用計(jì)數(shù)的, 那么對(duì)于一個(gè)是IS_LONG并且又是IS_REFERNCE的zval該如何表示呢?
為此, 我們創(chuàng)造了這個(gè)新的類型:

如圖所示, 引用是一種新的類型:zend_reference, 對(duì)于IS_REFERNCE類型的zval, zval.value.ref是一個(gè)指向zend_reference的指針, 它包含了引用計(jì)數(shù)和一個(gè)zval, 具體的zval的值是存在zval.value.ref->val中的.
所以對(duì)于IS_LONG的引用來說, 就用一個(gè)類型是IS_REFERNCE的zval, 它指向一個(gè)zend_reference, 而這個(gè)zend_reference->val中是一個(gè)類型為IS_LONG的zval.
Change On Write
PHP采用引用計(jì)數(shù)來做簡(jiǎn)單的垃圾回收, 考慮如下的代碼:
<?php1. $val = "laruence";2. $ref = &$val;3. $copy = $val;?>
$ref和$val是指向同一個(gè)zval的引用, 在PHP5的時(shí)候, 我們是通過一個(gè)引用計(jì)數(shù)為2, 并且引用標(biāo)志位為1來表示這種情況, 當(dāng)把$val復(fù)制給$copy(line 3)的時(shí)候, 我們發(fā)現(xiàn)$val是一個(gè)計(jì)數(shù)大于1的引用, 所以要產(chǎn)生Change on write, 也就是分離. 所以我們需要復(fù)制這個(gè)zval.
而在PHP7中, 情況就變得簡(jiǎn)單了很多, 首先在引用賦值給$ref(line 2)的時(shí)候, 生成一個(gè)IS_REFERNCE類型, 然后因?yàn)榇藭r(shí)有倆個(gè)變量引用它所以zend_reference這個(gè)結(jié)構(gòu)的引用計(jì)數(shù)zval.value.ref->gc.refcount為2.
再隨后的賦值給$copy(line 3)的時(shí)候, 發(fā)現(xiàn)$val是一個(gè)引用, 于是讓$copy指向的是zval.value.ref->val, 也就是字符串值為laruence的zval, 然后把zval的引用計(jì)數(shù)+1, 也就是zval.value.ref->val.value.str.gc.refcount為2. 并沒有產(chǎn)生復(fù)制.
從而這就很好的解決了上一章所說的PHP5的那個(gè)經(jīng)典的問題, 比如我們?cè)赑HP7下運(yùn)行上一章的那個(gè)問題, 我們得到的結(jié)果是:
$ php-7.0/sapi/cli/php /tmp/1.php
Used 0.00021380008539
Used 0.00020173048281
可見確實(shí)沒有發(fā)生復(fù)制, 從而不會(huì)產(chǎn)生任何的性能問題.
以上所述是小編給大家介紹的PHP7內(nèi)核之Reference詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)金聰精品網(wǎng)站的支持!
1.軟件源碼推廣展示:目的展示軟件相關(guān)功能,接收技術(shù)學(xué)習(xí)者測(cè)試、測(cè)評(píng);
2.教程課程信息展示:展示課程信息,傳授課程各階段內(nèi)容;
3.設(shè)計(jì)素材圖片展示:展示素材設(shè)計(jì)理念、思維方式、傳播設(shè)計(jì)理念;
4.福利優(yōu)惠信息展示:分享各類最新的福利信息,各種優(yōu)惠信息展示;
以上分享目的僅供學(xué)習(xí)、參考使用,請(qǐng)勿用于其他用途,如果想商業(yè)使用或者代理,請(qǐng)自行聯(lián)系版權(quán)方獲取授權(quán)。任何未獲取授權(quán)的商業(yè)使用與本站無關(guān),請(qǐng)自行承擔(dān)相應(yīng)責(zé)任。
本站不存儲(chǔ)任何資源文件,敬請(qǐng)周知!
如果您認(rèn)為本頁信息內(nèi)容侵犯了您的相關(guān)權(quán)益(包含但不限于:著作權(quán)、首發(fā)權(quán)、隱私權(quán)等權(quán)利),或者您認(rèn)為自己是此信息的權(quán)利人但是此信息不是自己發(fā)布的,可以直接版權(quán)舉報(bào)投訴,我們會(huì)根據(jù)網(wǎng)站注冊(cè)協(xié)議、資源分享協(xié)議等協(xié)議處理,以保護(hù)您的合法權(quán)益。
本網(wǎng)站采用 BY-NC-SA 協(xié)議進(jìn)行授權(quán) 轉(zhuǎn)載請(qǐng)注明原文鏈接:PHP7內(nèi)核之Reference詳解

侵權(quán)舉報(bào)/版權(quán)申訴



