上週咱們從底層的角度介紹了php變量從生成->常量賦值->銷燬的完整生命週期(不瞭解的同窗能夠翻看一下前面的文章php底層原理之變量(一)),可是咱們留了一個思考,不知道你們有答案了沒,變量之間的賦值在底層又是如何實現的呢?php
php變量的zval結構,咱們已經介紹了不少遍了,這裏咱們就再也不多做介紹了。可是對於zval結構體中的refcount__gc
和is_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");
若是你喜歡個人文章,請點贊支持我下,並歡迎關注個人專欄,每週都會有原創且有深度的文章奉上喲~