今天群裡面的一位小夥伴問我關於PHP變數中refcount的問題,當時回答給他了,發現自己沒注意到一個細節,記錄下來。
什麼是refcount
“zval結構體中有四個欄位,其含義分別為:
屬性名稱 含義 預設值
refcount__gc 表示引用計數 1
is_ref__gc 表示是否為引用 0
value 儲存變數的值
type 變數具體的類型”
摘錄來自: Reeze Xia. “TIPI: 深入理解PHP核心”。
refcount是php用來對zval變數引用次數技術的一個變數值。
它是一個計數器,用來儲存有多少符號表有多少符號指向該zval。在變數產生時,其refcount=1,賦值操作$a = $b會令zval的refcount加1,zval的refcount如果減少到0,會釋放該zval所佔的記憶體空間。
問題是什嗎?
小夥伴原問題是為什麼下面的計數會是3.
因為照上面的說法zval $a在被賦值為100的時候應該為1,$b = $a 的時候應該再加1,那麼debug_zval_dump()函數照理來說應該顯示2,而不應該顯示3。
當時我的回答是,初始化的時候值為1,賦值的時候再加1,賦值給$b的時候再加1,所以是3。
但是後來他提出,使用xdebug_zval_dump()出來refcount的值是2。
那麼,我之前的答案就是錯的,慚愧,學藝不精。
於是我找了一些資料來研究兩個函數之間處理的差異。
下面就是差異的原因。
PHP's debug_zval_dump takes a variable as argument for analysis and is thus also bound to the same splitting rules as outlined earlier. This means that's not really well suited for dumping a zval's internal structure as it would always modify the zval. Besides adding 1 to the refcount field, it could also force a split resulting in unexpected output:
<?php
$a = 42;
debug_zval_dump($a);
?>
shows:
long(42) refcount(2)
Xdebug has a similar function to display a zval's internal data: xdebug_debug_zval. This function does requires not a variable to be passed as its argument, but instead requires a variable name to be passed in. With this, the manipulation of the zval is avoided and the proper values are shown:
<?php
$a = 42;
xdebug_debug_zval('a');
?>
which shows:
a: (refcount=1, is_ref=0)=42
所以單純的$a的refcount=0,賦值操作會+1