摘要:但是對(duì)于結(jié)構(gòu)體中的和字段我們一直都沒(méi)有詳細(xì)介紹過(guò),而這兩個(gè)字段其實(shí)是和變量之間賦值的原理有著密切的關(guān)系的。
上周我們從底層的角度介紹了php變量從生成->常量賦值->銷(xiāo)毀的完整生命周期(不了解的同學(xué)可以翻看一下前面的文章php底層原理之變量(一)),但是我們留了一個(gè)思考,不知道大家有答案了沒(méi),變量之間的賦值在底層又是如何實(shí)現(xiàn)的呢?
變量之間賦值php變量的zval結(jié)構(gòu),我們已經(jīng)介紹了很多遍了,這里我們就不再多作介紹了。但是對(duì)于zval結(jié)構(gòu)體中的refcount__gc和is_ref__gc字段我們一直都沒(méi)有詳細(xì)介紹過(guò),而這兩個(gè)字段其實(shí)是和變量之間賦值的原理有著密切的關(guān)系的。所以,我們這次從幾個(gè)例子入手,了解這兩個(gè)字段的變化和由此帶來(lái)的原理知識(shí)
寫(xiě)時(shí)復(fù)制原理舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = $a; xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=0)="許錚的技術(shù)成長(zhǎng)之路" b: (refcount=2, is_ref=0)="許錚的技術(shù)成長(zhǎng)之路"
看到這里,大家可能會(huì)比較蒙。不是變量賦值了么?應(yīng)該發(fā)生值拷貝了呀?怎么兩個(gè)變量的引用計(jì)數(shù)不是1,而是2呢?
那是因?yàn)椋?strong>php在設(shè)計(jì)的時(shí)候,為了節(jié)省內(nèi)存,所以在變量之間賦值時(shí),對(duì)于值相同的兩個(gè)變量,會(huì)共用一塊內(nèi)存,也就是會(huì)在全局符號(hào)表內(nèi)將變量b的變量指針指向變量a指向的同一個(gè)zval結(jié)構(gòu)體,而只有當(dāng)變量的zval結(jié)構(gòu)發(fā)生變化時(shí),才會(huì)發(fā)生變量容器復(fù)制的內(nèi)存變化,也因此叫做寫(xiě)時(shí)復(fù)制原理
那什么時(shí)候會(huì)發(fā)生寫(xiě)時(shí)復(fù)制原理呢?
寫(xiě)時(shí)復(fù)制原理觸發(fā)時(shí)機(jī):
php在修改一個(gè)變量時(shí),如果發(fā)現(xiàn)變量的refcount>1,則會(huì)執(zhí)行變量容器的內(nèi)存復(fù)制
舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = $a; //此時(shí)變量a和變量b共同指向同一個(gè)變量容器,即refcount>1 $b = "許錚的技術(shù)成長(zhǎng)之路1" //觸發(fā)寫(xiě)時(shí)復(fù)制機(jī)制 xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=1, is_ref=0)="許錚的技術(shù)成長(zhǎng)之路" b: (refcount=1, is_ref=0)="許錚的技術(shù)成長(zhǎng)之路1"寫(xiě)時(shí)改變?cè)?/b>
變量之間的賦值我們搞清楚了,那么變量和引用之間的賦值呢?我們還是通過(guò)舉例來(lái)說(shuō)明
舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = &$a; xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路" b: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路"
此時(shí),我們發(fā)現(xiàn),變量a和b的refcount還是2,只不過(guò)is_ref變成了1,那是因?yàn)樵趯⒆兞縜引用賦值給變量b時(shí),在原變量容器上作了修改,將is_ref變成了1,且refcount+1
那如果引用賦值的基礎(chǔ)上又發(fā)生了變量的改變了呢?
舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = &$a; $b = "許錚的技術(shù)成長(zhǎng)之路1" xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路1" b: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路1"
是不是覺(jué)得很神奇?變量b和變量a的值一起發(fā)生改變了~其實(shí)這是因?yàn)橛|發(fā)了寫(xiě)時(shí)改變?cè)?/b>
寫(xiě)時(shí)改變?cè)?/b>觸發(fā)時(shí)機(jī):
is_ref為1的變量容器在被賦值之前,優(yōu)先檢查變量容器的is_ref是否等于1,如果為1,則不進(jìn)行寫(xiě)時(shí)復(fù)制,而是在原變量容器基礎(chǔ)上作內(nèi)容修改;而如果將is_ref為1的變量容器賦值給其他變量時(shí),則會(huì)立即觸發(fā)寫(xiě)時(shí)復(fù)制
那么如果把剛剛舉得幾個(gè)例子合并在一起呢?最后結(jié)果又是什么呢?
舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = $a; $c = &$a; xdebug_debug_zval("a", "b", "c");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路" b: (refcount=1, is_ref=0)="許錚的技術(shù)成長(zhǎng)之路" c: (refcount=2, is_ref=1)="許錚的技術(shù)成長(zhǎng)之路"
整體執(zhí)行過(guò)程是這樣的,當(dāng)執(zhí)行到第二行時(shí),變量容器的refcount會(huì)變成2,變量a和變量b共享同一個(gè)變量容器;當(dāng)執(zhí)行到第三行時(shí),因?yàn)閷⒆兞縜的引用賦值給變量c,但是變量b和變量a已經(jīng)共享了同一個(gè)變量容器,此時(shí)變量容器如果要發(fā)生改變,因?yàn)閞efcount>2,所以會(huì)發(fā)生寫(xiě)時(shí)復(fù)制,將變量a和變量b分離,之后將變量a引用賦值給變量c時(shí),則會(huì)原基礎(chǔ)上進(jìn)行修改,is_ref變成1,且refcount變成2
思考那么,下面的這個(gè)例子,最終結(jié)果是什么呢?歡迎大家在下方留言或私信我~
舉例:
$a = "許錚的技術(shù)成長(zhǎng)之路"; $b = $a; $c = &$a; $d = $a; $e = "許錚的技術(shù)成長(zhǎng)之路1" $a = $e; xdebug_debug_zval("a", "b", "c", "d", "e");
如果你喜歡我的文章,請(qǐng)點(diǎn)贊支持我下,并歡迎關(guān)注我的專(zhuān)欄,每周都會(huì)有原創(chuàng)且有深度的文章奉上喲~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/31087.html
摘要:數(shù)組是最常用的數(shù)據(jù)類(lèi)型,同時(shí)容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在中是如何實(shí)現(xiàn)的呢首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ)哈希表哈希表,顧名思義,即將不同的關(guān)鍵字映射到不同單元的一種數(shù)據(jù)結(jié)構(gòu)。 數(shù)組是PHPer最常用的數(shù)據(jù)類(lèi)型,同時(shí)php容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在php中是如何實(shí)現(xiàn)的呢? 首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ) 哈希...
摘要:對(duì)于來(lái)說(shuō),變量有全局變量和局部變量之分那么,他們都是存儲(chǔ)到一個(gè)哈希表內(nèi)了么其實(shí)不是的,變量存儲(chǔ)也有作用域的概念。 上次跟大家講了垃圾回收機(jī)制后,有些小伙伴對(duì)底層原理比較感興趣,私信問(wèn)我了一些關(guān)于變量的相關(guān)知識(shí),既然大家對(duì)變量比較感興趣,那么這次我們來(lái)系統(tǒng)的講一下變量的底層原理 變量結(jié)構(gòu) 首先,我們還是先擺上我們的zval結(jié)構(gòu)體,即php所有變量都會(huì)以zval結(jié)構(gòu)體的形式實(shí)現(xiàn) struc...
摘要:總結(jié)垃圾回收機(jī)制以的引用計(jì)數(shù)機(jī)制為基礎(chǔ)以前只有該機(jī)制同時(shí)使用根緩沖區(qū)機(jī)制,當(dāng)發(fā)現(xiàn)有存在循環(huán)引用的時(shí),就會(huì)把其投入到根緩沖區(qū),當(dāng)根緩沖區(qū)達(dá)到配置文件中的指定數(shù)量后,就會(huì)進(jìn)行垃圾回收,以此解決循環(huán)引用導(dǎo)致的內(nèi)存泄漏問(wèn)題開(kāi)始引入該機(jī)制 php垃圾回收機(jī)制,對(duì)于PHPer來(lái)說(shuō)是一個(gè)不陌生但是又不是很熟悉的內(nèi)容。那么php是怎么實(shí)現(xiàn)對(duì)不需要的內(nèi)存進(jìn)行回收的呢? php變量的內(nèi)部存儲(chǔ)結(jié)構(gòu) 首先還是...
摘要:弱類(lèi)型語(yǔ)言一個(gè)變量的類(lèi)型并不是一開(kāi)始就確定不變的,運(yùn)行中才會(huì)確定并可能發(fā)生隱式或顯示的類(lèi)型轉(zhuǎn)換。引擎組件的模式降低內(nèi)部耦合。 一、PHP設(shè)計(jì)理念及特點(diǎn) 多進(jìn)程模型:由于PHP是多進(jìn)程模型,不同請(qǐng)求間互不干涉,這樣保證了一個(gè)請(qǐng)求掛掉不會(huì)對(duì)全盤(pán)服務(wù)造成影響,PHP也早支持多線程模型。弱類(lèi)型語(yǔ)言:一個(gè)變量的類(lèi)型并不是一開(kāi)始就確定不變的,運(yùn)行中才會(huì)確定并可能發(fā)生隱式或顯示的類(lèi)型轉(zhuǎn)換。引擎(Ze...
摘要:雖然有了十全的計(jì)劃,但如何高效率去記住上面那么多東西是一個(gè)大問(wèn)題,看看我是怎么做的。 前言 前一篇文章講述了我在三月份毫無(wú)準(zhǔn)備就去面試的后果,一開(kāi)始心態(tài)真的爆炸,但是又不服氣,一想到每次回來(lái)后家人朋友問(wèn)我面試結(jié)果的期待臉,越覺(jué)得必須付出的行動(dòng)來(lái)證明自己了。 面經(jīng)傳送門(mén):一個(gè)1年工作經(jīng)驗(yàn)的PHP程序員是如何被面試官虐的? 下面是我花費(fèi)兩個(gè)星期做的準(zhǔn)備,主要分三部分: 有計(jì)劃——計(jì)劃好...
閱讀 2892·2019-08-30 15:55
閱讀 1995·2019-08-30 14:02
閱讀 1232·2019-08-29 15:23
閱讀 1001·2019-08-29 11:27
閱讀 457·2019-08-26 11:43
閱讀 3184·2019-08-26 10:32
閱讀 1249·2019-08-23 14:41
閱讀 3296·2019-08-23 14:41