今天絕對是興奮的一天,不單單是週五這個特殊的日子(週六日能夠休息啦),也不是弄清了某wordpress插件的功能流程,更不是再次買到了想吃好久的手撕牛肉,而是真正解決了一直以來(嘿嘿,其實時間不長)對PHP中變量引用和函數傳參的疑惑。 php
故事源於一個巧合,我在查PHP變量做用域的東西時看到的文章(後面再附上地址,無心侵權做者大大)。由於這篇只講變量和函數傳參的,因此其餘的不涉及了(也無力涉及哈哈)。 html
看這麼一句 wordpress
$a = 'abc';
當咱們定義一個變量時,PHP會爲咱們作兩件事情 函數
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount; zend_uchar type; /* active type */ zend_uchar is_ref; };這個就是zval的C語言定義,在PHP中變量都是用這個結構體來存儲,其中成員zvalue_value是一個聯合體,用以存儲底層強類型變量,這種結構也是實現PHP弱類型的關鍵,在這裏只須要清楚有這麼個結構體就能夠了。
$a = 12; $b = $a;
執行到第二句時,會在symbol_table中新加入b,令b指向a所指向的那個zval結構體,這個zval的refcount加1, 到這根據以往的知識可能就有疑問了,b指向a指向的結構體不就是引用了嘛,再看下面代碼: ui
$a = 12; $b = &$a;
那這算什麼?執行第二句時,除了在symbol_table中加入b令其指向a指向的那個zval並使refcount加1外,還會改變該zval中is_ref值爲1(默認爲零應該),is_ref是個bool值,用來標識這個變量是不是屬於引用集合(reference set),這樣這個zval就與一開始不太同樣了。 spa
來看更復雜的: .net
$a = 12; $b = $a; $c = &$a;
前兩行執行完與前面第一個例子是同樣的,此時$a和$b指向的zval的refcount值爲2,is_ref爲0,表示有兩個symbol指向這個zval, is_ref爲0,表示zval不屬於引用集合,當第三行執行時時,發現zval的refcount不爲1且不是引用集合,那麼便爲$b複製一個zval結構體,同時$a的zval的refcount減1,又由於多了$c指向原來的zval,因此又refcount加1,仍是2,同時$a也是$c的zval的is_ref置1,表示這個zval屬於引用集合了,$b的zval則是新的zval(refcount=1,is_ref=0)。 插件
第二、3行交換位置最後的結果相同,只不過zval的變化順序不一樣,最終仍然是$a與$c指向同一個zval(refcount=2,is_ref=1),$b指向的zval(refcount=1,is_ref=0)。 code
再有$d、$e等原理同樣。 orm
當更改變量時也會發生zval的新建與變化,原理同上,不細討論了,可參見:
當咱們明白了這個機制的時候,函數傳參就迎刃而解了:
$a = 12; function change($k){ $k = 1; } change(&$a); //至關於$k = &$a,接下來就知道怎麼辦了吧,$a的值是能夠改變的 change($a); //至關於$k = $a,你看,還用我說麼?好的,到這就差很少了,要是我寫的有點亂很差懂(不是深奧,我有自知之明的),好好研究下上面兩個網址。
恩,這篇寫的好累,休息休息