想要走到技術的天花板,那麼學習過程當中在於知其然且知其因此然。面試
今天咱們來討論一下PHP底層的寫時複製(也稱寫時分裂)。數組
首先咱們先來看看一段代碼:學習
兩段代碼的輸出結果相信各位都知道,可是咱們今天講講這之中發生了什麼。優化
下圖是PHP存儲變量的結構體(爲方便講解已寫了註釋),zend.h在Zend目錄下。spa
能夠看到,該結構體存儲了關於變量值,有幾個變量指向該結構體,變量類型,是否爲引用變量等信息。指針
那麼第一次打印發生了什麼呢?變量的信息進入了一個結構體,相關以下:blog
$name = ‘傍晚八點半’;
$myName = $name;內存
此時$name和$myName共用一個結構體的,refcount__gc爲2,開發
咱們發現,$myName = $name;這個過程當中並無主動變成兩個結構體(這也算PHP內部實現優化的一種,只用一個結構體,省了內存)。同步
那麼當代碼運行到 $myName = ‘gzchen’; 的時候,結構體如何變化呢?因爲第一次輸出時是兩個變量共用結構體,那麼此時更改其中一個變量,會不會致使兩個值一塊兒變化呢?純粹從結構體的邏輯來看,是有可能的,畢竟你們共用着這個結構體嘛。
那麼咱們看下第二次打印是怎麼樣的狀況,相關變化以下:
並無按照咱們所想的將$name和$myName同時改爲’gzchen’,而是複製多了一份結構體出來,兩個結構體分別對應着$name和$myName。
這個就是寫時複製(Copy-on-write,COW)在做怪,他沒有在$myName = $name;賦值的時候就分裂成兩個結構體,而是在咱們改寫其中一個變量時發生效果,屬於一種慢複製(也稱慢分裂)。
僞代碼以下:
咱們再看下另一段代碼:
輸出爲’b’,中途發生了什麼?
其實foreach遍歷過程當中,並非直接操做$arr(原數組)的,而是會將$arr複製出一個$arrcopy(其實是一個副本,我這裏以$arrcopy代替),foreach在遍歷過程當中操做的其實一直是$arrcopy,大概的流程是這樣:
和上面舉得例子實際上是一個道理,咱們能夠看出,剛開始($arr = $arrcopy)仍是共用一個結構體的,可是$arr[$k] = $v又再次賦值,發生了寫時複製,結構體就分裂了。
而後前面說過foreach操做的是$arrcopy,因此$arr的結構體指針就被停留在第一位了(由於結構體不同了,$arrcopy沒辦法同步給$arr賦值了)。
其實這類技術一般只會在面試中用到,平常開發會用這種寫法的人終究仍是少數,暫時看不明白的朋友也不用太在乎,只要知道有」寫時複製」這個狀況出現就好了。