php底層原理之變量(二)

上週咱們從底層的角度介紹了php變量從生成->常量賦值->銷燬的完整生命週期(不瞭解的同窗能夠翻看一下前面的文章php底層原理之變量(一)),可是咱們留了一個思考,不知道你們有答案了沒,變量之間的賦值在底層又是如何實現的呢?php

變量之間賦值

php變量的zval結構,咱們已經介紹了不少遍了,這裏咱們就再也不多做介紹了。可是對於zval結構體中的refcount__gcis_ref__gc字段咱們一直都沒有詳細介紹過,而這兩個字段實際上是和變量之間賦值的原理有着密切的關係的。因此,咱們此次從幾個例子入手,瞭解這兩個字段的變化和由此帶來的原理知識segmentfault

寫時複製原理

舉例:debug

$a = "許錚的技術成長之路";
$b = $a;
xdebug_debug_zval("a", "b");

結果:設計

a: (refcount=2, is_ref=0)='許錚的技術成長之路'
b: (refcount=2, is_ref=0)='許錚的技術成長之路'

看到這裏,你們可能會比較蒙。不是變量賦值了麼?應該發生值拷貝了呀?怎麼兩個變量的引用計數不是1,而是2呢?指針

那是由於,php在設計的時候,爲了節省內存,因此在變量之間賦值時,對於值相同的兩個變量,會共用一塊內存,也就是會在全局符號表內將變量b的變量指針指向變量a指向的同一個zval結構體,而只有當變量的zval結構發生變化時,纔會發生變量容器複製的內存變化,也所以叫作寫時複製原理code

那何時會發生寫時複製原理呢?生命週期

寫時複製原理觸發時機:
php在修改一個變量時,若是發現變量的refcount>1,則會執行變量容器的內存複製內存

舉例:get

$a = "許錚的技術成長之路";
$b = $a; //此時變量a和變量b共同指向同一個變量容器,即refcount>1
$b = "許錚的技術成長之路1" //觸發寫時複製機制
xdebug_debug_zval("a", "b");

結果:class

a: (refcount=1, is_ref=0)='許錚的技術成長之路'
b: (refcount=1, is_ref=0)='許錚的技術成長之路1'

寫時改變原理

變量之間的賦值咱們搞清楚了,那麼變量和引用之間的賦值呢?咱們仍是經過舉例來講明

舉例:

$a = "許錚的技術成長之路";
$b = &$a;
xdebug_debug_zval("a", "b");

結果:

a: (refcount=2, is_ref=1)='許錚的技術成長之路'
b: (refcount=2, is_ref=1)='許錚的技術成長之路'

此時,咱們發現,變量a和b的refcount仍是2,只不過is_ref變成了1,那是由於在將變量a引用賦值給變量b時,在原變量容器上做了修改,將is_ref變成了1,且refcount+1

那若是引用賦值的基礎上又發生了變量的改變了呢?

舉例:

$a = "許錚的技術成長之路";
$b = &$a;
$b = "許錚的技術成長之路1"
xdebug_debug_zval("a", "b");

結果:

a: (refcount=2, is_ref=1)='許錚的技術成長之路1'
b: (refcount=2, is_ref=1)='許錚的技術成長之路1'

是否是以爲很神奇?變量b和變量a的值一塊兒發生改變了~其實這是由於觸發了寫時改變原理

寫時改變原理觸發時機:
is_ref爲1的變量容器在被賦值以前,優先檢查變量容器的is_ref是否等於1,若是爲1,則不進行寫時複製,而是在原變量容器基礎上做內容修改;而若是將is_ref爲1的變量容器賦值給其餘變量時,則會當即觸發寫時複製

那麼若是把剛剛舉得幾個例子合併在一塊兒呢?最後結果又是什麼呢?

舉例:

$a = "許錚的技術成長之路";
$b = $a; 
$c = &$a;
xdebug_debug_zval("a", "b", "c");

結果:

a: (refcount=2, is_ref=1)='許錚的技術成長之路'
b: (refcount=1, is_ref=0)='許錚的技術成長之路'
c: (refcount=2, is_ref=1)='許錚的技術成長之路'

總體執行過程是這樣的,當執行到第二行時,變量容器的refcount會變成2,變量a和變量b共享同一個變量容器;當執行到第三行時,由於將變量a的引用賦值給變量c,可是變量b和變量a已經共享了同一個變量容器,此時變量容器若是要發生改變,由於refcount>2,因此會發生寫時複製,將變量a和變量b分離,以後將變量a引用賦值給變量c時,則會原基礎上進行修改,is_ref變成1,且refcount變成2

思考

那麼,下面的這個例子,最終結果是什麼呢?歡迎你們在下方留言或私信我~

舉例:

$a = "許錚的技術成長之路";
$b = $a; 
$c = &$a;
$d = $a;
$e = "許錚的技術成長之路1"
$a = $e;
xdebug_debug_zval("a", "b", "c", "d", "e");

若是你喜歡個人文章,請點贊支持我下,並歡迎關注個人專欄,每週都會有原創且有深度的文章奉上喲~

相關文章
相關標籤/搜索