php是弱型別語言,它可以儲存任何的資料型別。但是php是使用c語言編寫的,而c語言是強型別語言。每個變數都有固定的型別,不能隨意改變變數的型別。
在zend/zend.h中,檢視結構體:
zval結構體就是通常用到的php變數在核心總的表示形式,在zval結構體中,可以看到四個成員變數,分別是:
zvalue_value value:變數的值,php變數的值就儲存在這裡。
zend_uint refcount:變數引用數,變數引用計算器。
zend_uchar type:變數的型別。
zend_uchar is_ref:變數是否被引用。
zval結構體的value成員變數是zvalue_value聯合體,php能夠保持任何的結構型別就因為這個聯合體。從zvalue_value聯合體的成員變數中可以看到,不同的型別會儲存到不同的成員變數中,這樣就實現了php變數可以儲存任何資料型別。例如,當變數是整數型別時,會儲存到value的lval成員變數中,而當變數的型別是字串時,又回儲存到value的str成員變數中。
以上是解決了php變數可以儲存任意型別的問題,但是zend引擎是怎麼知道這個變數儲存的是什麼型別呢,在zval結構中有個type成員變數,這個成員變數就是儲存乙個php變數的型別。
我們都知道,php是不支援指標的,但是如果希望兩個變數同事指向同一塊記憶體怎麼辦?為了解決這個問題,php核心中使用了引用計數器。
zval結構中有兩個成員變數用於引用計數器:
is_ref:bool值,標識變數是否是引用集合
refcount:計算指向引用集合的變數個數
<?php
$a = "this is leju";
乙個zval結構的實體稱為zval容器,在php語言層建立乙個變數就會相應的在php核心中建立乙個zval容器。因為上面的**建立了乙個變數$a,所以在php核心中會建立乙個zval容器。又因為這個變數不是乙個引用,所以zval容器的is_ref等於false,並且refcount等於1.
<?php
$a = "this is leju";
$b = $a;
上面這段**中建立了兩個變數 $a和$b,所以php核心中會建立兩個zval容器來儲存它們,變數b被賦予變數a的值,由於變數b並不是引用a,所以變數a的is_ref變數的值是false,但是使用xdebug列印變數a的話,會發現refcount等於2,這是為啥呢?
首先來了解下php寫時複製(copy on write)機制。
寫時複製是乙個解決記憶體復用的方法,例如上面的**,如果簡單的把a的值賦值給b,那麼就又兩個 this is leju 字串的複製,這樣不利於記憶體的復用,因為完全可以使用乙個 this is leju的字串的複製完成工作,所以簡單的賦值是非常耗記憶體的,寫時複製就是為了解決這種問題而創造的,那什麼是寫時複製呢,就是當變數的值改變時才進行的記憶體的複製。
當將變數a的值賦值給變數b時,變數a的refcount增加1,所以這時候變數a和變數b是指向同一記憶體塊的,當改變變數a的值時,發現refcount的值變回1,所以這個時候變數a和變數b指向不同的記憶體塊,這就是寫時複製機制,就是兩個指向同一記憶體塊的變數,當其中乙個變數的值發生變化,才會另外建立乙個記憶體塊去儲存新的值,其實寫時複製也是一種引用,只不過這種引用會受變數值的改變而破壞罷了。
如果顯示的引用變數,即$b = &a;變數的is_ref欄位會設定1,表示此變數被引用,另外引用計數器(refcount)也相應的加1,在php核心中通過以下**判斷是否複製變數:
if ((*varval)->is_ref || (*varval)->refcount < 2){
return *varval;
推薦一本書,《php核心技術與最佳實踐》 非常好看~
PHP變數在核心中的實現
我們都知道php是乙個弱型別語言,它的變數理論上可以儲存任何型別的資料。那麼,php的變數在核心中究竟是怎麼實現的呢?在php核心中,變數稱為zval,變數的值稱為zend value,注意這是兩個不同的東西。php中變數的記憶體是通過引用計數的方式進行管理的,在php7之前,zval容器中有兩個位...
PHP核心中的HashTable
本文和大家分享的主要是php核心的hashtable相關使用,希望通過本文的分享,對大家學習php有所幫助。typedef struct bucket bucket typedef struct hashtable hashtable 這個是乙個簡化過的雜湊表結構 bucket是乙個鍊錶,而 has...
PHP變數在zend核心中的儲存方式
php中的變數可以儲存任何的資料型別,這是因為它是弱型別語言。但php是用c語言編寫的,c語言是強型別語言,每個變數都有固定的型別,不能隨意改變變數的型別 可以通過強制型別轉變,不過有可能出現問題 在zend引擎中是怎樣可以做到乙個變數儲存任何型別的呢?在zend zend.h標頭檔案中,會發現下面...