1、引用變數的定義 在PHP 中引用的意思是:不同的名字訪問同一個變數內容.使用&表示 使用 & 會使(如$a = &$b)指向同一個記憶體地址(這並不像 C 的指針:例如你不能對他們做指針運算,他們並不是實際的記憶體地址),一個發生改變,另一個也會發生改變 2、使用 memory_get_usage( ...
1、引用變數的定義
在PHP 中引用的意思是:不同的名字訪問同一個變數內容.使用&表示
使用 & 會使(如$a = &$b)指向同一個記憶體地址(這並不像 C 的指針:例如你不能對他們做指針運算,他們並不是實際的記憶體地址),一個發生改變,另一個也會發生改變
2、使用 memory_get_usage() 函數觀察記憶體的變化
2.1、不使用 &
因為PHP 中COW(Copy On Write) 會導致賦值是引用上一個變數的地址(記憶體不會發生太大變化),只有在發生 寫 操作的時候,才會開闢新的記憶體地址
$a = range(0,1000); var_dump(memory_get_usage()); $b = $a; var_dump(memory_get_usage()); $a = range(0,1000); var_dump(memory_get_usage());
運行結果:
記憶體在第一次和第二次並沒有太大的差異,第三次產生較大差異
2.2、使用 &
$a = range(0,1000); var_dump(memory_get_usage()); $b = &$a; var_dump(memory_get_usage()); $a = range(0,1000); var_dump(memory_get_usage());
運行結果:
記憶體在過程中基本沒有發生變化,雖然第三步進行了寫操作,但是 $a,$b引用的同一個地址,就不需要開闢新地址
3、使用xdebug 觀察
xdebug 的安裝方法 網上很多,這裡不細講(php 的一個擴展插件而已)
3.1、不使用 &
//zval 變數容器 $a = range(0, 3); xdebug_debug_zval('a'); //定義變數b,把a的值賦值給b $b = $a; xdebug_debug_zval('a'); //修改a $a = range(0, 3); xdebug_debug_zval('a');
運行如下:
refcount用以標識指向這個zval變數容器的變數個數
is_ref(bool),標識此變數是否屬於引用集合
第二步只進行了COPY 操作,使$a , $b 指向同一個記憶體地址, refcount = 2,而第三步 發生了寫操作(is_ref=0 不是引用),重新開闢了記憶體地址,refcount= 1
3.2、使用 &
//zval 變數容器 $a = range(0, 3); xdebug_debug_zval('a'); //定義變數b,把a的值賦值給b $b = &$a; xdebug_debug_zval('a'); //修改a $a = range(0, 3); xdebug_debug_zval('a');
運行結果:
採用了 引用(&),所以 從第二步開始 refcount = 2,is_ref = 1(引用) ,引用狀態下不開闢新的記憶體地址;
4、特殊的引用(對象)
php 中 OBJECT 本身就是引用傳值(自 PHP 5 起,new 自動返回引用,因此在此使用 =& 已經過時了並且會產生 E_STRICT 級別的消息。)
//對象本身就是引用傳遞 class Person { public $name = 'zs'; } $p1 = new Person; xdebug_debug_zval('p1'); $p2 = $p1; xdebug_debug_zval('p1'); $p2->name = 'ls'; xdebug_debug_zval('p1');
運行結果:
OBJECT 賦值情況下 會共用記憶體地址,但本身又不是引用。
5、unset
//unset 只會取消引用,不會銷毀空間 $a = ''; xdebug_debug_zval('a'); $b = &$a; xdebug_debug_zval('a'); unset($b); xdebug_debug_zval('a');
運行結果:
所以在第一步的時候 refcount = 0
對應 引用(&),unset只會取消引用,而不會銷毀記憶體地址
5、總結
通過對 is_ref 判斷是否是引用變數,如果是引用變數,修改時直接修改(原記憶體地址),否則,則需要進行 分離(重新開闢新地址),而 usset 變數只是取消該變數的引用,而不會消除記憶體地址,只有當refcount = 0;記憶體才有可能被回收