之前說過引用(REFERENCE)在PHP5的時候是一個標誌位, 而在PHP7以後我們把它變成了一種新的類型:IS_REFERNCE. 然而引用是一種很常見的應用, 所以這個變化帶來了很多的變化, 也給我們在做PHP7開發的時候, 因為有的時候疏忽忘了處理這個類型, 而帶來不少的bug.
最簡單的情況, 就是在處理各種類型的時候, 從此以後我們要多考慮這種新的類型, 比如在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; }
如果大家自己寫的擴充, 如果忘了考慮這種新的類型, 那麼就會導致問題.
為什麼?
##那麼既然這種新類型會帶來這麼多問題, 那麼當時為什麼要用把引用變成一種類型呢? 為什麼不還是使用一個標誌位呢?一句話來說, 就是我們不得不這麼做. -_#前面說到, Hashtable直接儲存的是zval, 這樣在符號表中, 兩個zval如何共用一個數值呢? 對於字串等複雜型別來說還好, 我們貌似可以在zend_refcounted結構中加入一個標誌位來表明是引用來解決, 然而這個也會遇到Change On Write帶來的複製, 但是我們知道在PHP7中, 一些類型是直接存儲在zval中的, 比如IS_LONG, 但是引用類型是需要引用計數的, 那麼對於一個是IS_LONG並且又是IS_REFERNCE的zval該如何表示呢?為此, 我們創造了這個新的類型:如圖所示, 引用是一種新的類型:zend_reference, 對於IS_REFERNCE類型的zval, zval.value.ref是一個指向zend_reference的指標, 它包含了引用計數和一個zval, 具體的zval的值是存在zval.value.ref->val中的.所以對於IS_LONG的引用來說, 就用一個類型是IS_REFERNCE的zval, 它指向一個zend_reference, 而這個zend_reference->val中是一個型別為IS_LONG的zval.Change On Write
PHP採用引用數來做簡單的垃圾回收, 考慮如下的程式碼:<?php 1. $val = "laruence"; 2. $ref = &$val; 3. $copy = $val; ?>
$ php-7.0/sapi/cli/php /tmp/1.php Used 0.00021380008539 Used 0.00020173048281
PHP教程》
以上是深入理解PHP7內核之Reference的詳細內容。更多資訊請關注PHP中文網其他相關文章!