[TOC]
* * * * *
### 一. 概念
* 即用不同的名字訪問同一個變量內容;
### 二. 定義符號
* 使用 & 符號;
### 三. COW機制
寫時復制(Copy-on-Write,也縮寫為COW),顧名思義,就是在寫入時才真正復制一份內存進行修改;
~~~
$a = range(0,1000);
var_dump(memory_get_usage()); // 打印內存使用情況
$b = $a;
var_dump(memory_get_usage());
// 此時 , $a 與 $b 指向同一個內存空間, 并不會因為$b的創建而開辟另一塊內存空間
$a = range(0,1000);
var_dump(memory_get_usage());
// 此時, $b還是指向最初的空間, 而$a會指向新的內存空間;
~~~
### 四. PHP引用變量的原理
~~~
$a = range(0,1000);
var_dump(memory_get_usage());
$b = &$a;
var_dump(memory_get_usage());
// 此時 , $a 與 $b 在一般情況下永遠指向同一個內存空間, 并不會因為誰的更改而開辟另一塊內存空間
$a = range(0,1000);
var_dump(memory_get_usage());
// 此時, $a 與 $b 還是指向最初的空間; 改變的只是內存空間的值;
~~~
### 五. xdebug_debug_zval()函數 的使用
* 每個php變量存在一個叫"zval"的變量容器中。
* 一個zval變量容器,除了包含變量的類型和值,還包括兩個字節的額外信息。
* 一個是"is_ref",是個bool值,用來標識這個變量是否是屬于引用集合(reference set)。
* 通過這個字節,php引擎才能把普通變量和引用變量區分開來。
* 由于php允許用戶通過使用&來使用自定義引用,zval變量容器中還有一個內部引用計數機制,來優化內存使用。
* 另一個額外字節是"refcount",用以表示指向這個zval變量容器的變量(也稱符號即symbol)個數。
~~~
$a = 123;
xdebug_debug_zval('a'); // a:(refcount=0, is_ref=0)int 123
$b = $a;
xdebug_debug_zval('a'); // a:(refcount=0, is_ref=0)int 123
$c = &$a;
xdebug_debug_zval('a'); // a:(refcount=2, is_ref=1)int 123
~~~
~~~
$a = range(0,3);
xdebug_debug_zval('a');
$b = $a;
xdebug_debug_zval('a');
$c = &$a;
xdebug_debug_zval('a');
打印結果 :
a:
(refcount=1, is_ref=0)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
a:
(refcount=2, is_ref=0)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
a:
(refcount=2, is_ref=1)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
~~~
### 六. 對象本身就是引用傳值
~~~
class Person
{
public $name = "zhangsan";
}
$p1 = new Person;
xdebug_debug_zval('p1');
$p2 = $p1;
xdebug_debug_zval('p1');
$p2->name = "zhouliuwan";
xdebug_debug_zval('p1');
打印結果 :
p1:(refcount=1, is_ref=0)
object(Person)[1]
public 'name' => (refcount=1, is_ref=0)string 'zhangsan' (length=8)
p1:(refcount=2, is_ref=0)
object(Person)[1]
public 'name' => (refcount=1, is_ref=0)string 'zhangsan' (length=8)
p1:(refcount=2, is_ref=0)
object(Person)[1]
public 'name' => (refcount=0, is_ref=0)string 'zhouliuwan' (length=10) // name值已經發生改變
~~~