----- 最近更新時(shí)間【2021-12-15】-----
本節(jié)目錄預(yù)覽:
》一先匪、概念
》二重斑、變量的存儲(chǔ)方式
》三尘执、變量的引用機(jī)制
》四絮姆、從zval變量容器底層去了解引用
》五隆箩、unset與引用
》六、對(duì)象與引用
》七阀湿、測(cè)試題
》八、參考文獻(xiàn)
一幢尚、概念
在PHP中引用意味著用不同的名字訪問(wèn)同一個(gè)變量?jī)?nèi)容。
定義方式:使用&
符號(hào)
二翅楼、變量的存儲(chǔ)方式
在講解變量的引用之前尉剩,我們先來(lái)了解一下變量的存儲(chǔ)方式。
下面以一個(gè)例子來(lái)說(shuō)明:
// 1毅臊、定義一個(gè)變量$a
$a = '111'; //當(dāng)我們定義一個(gè)變量$a時(shí)理茎,那么程序就會(huì)為它在內(nèi)存當(dāng)中開(kāi)啟一個(gè)內(nèi)存空間,此時(shí)$a就指向這個(gè)內(nèi)存空間(內(nèi)存空間里存儲(chǔ)著相應(yīng)的值)管嬉。
// 2皂林、定義一個(gè)變量$b,然后將$a的值賦值給$b
$b = $a; //這時(shí)程序不會(huì)為變量$b再開(kāi)啟一個(gè)內(nèi)存空間蚯撩,這里涉及到了php的COW機(jī)制础倍。
//只有對(duì)$a或$b中的其中一個(gè)進(jìn)行修改時(shí),才會(huì)進(jìn)行復(fù)制一份內(nèi)存胎挎。
//3沟启、修改$a
$a = '222'; //復(fù)制一份內(nèi)存,用于存儲(chǔ)修改后的值犹菇。
附:COW(copy on write)是內(nèi)存優(yōu)化的常見(jiàn)手段德迹,在php中也采用了這種方式來(lái)優(yōu)化內(nèi)存。COW:寫(xiě)時(shí)復(fù)制揭芍,即只有當(dāng)對(duì)其中一個(gè)或多個(gè)變量進(jìn)行寫(xiě)操作的時(shí)候胳搞,才會(huì)復(fù)制一份內(nèi)存,對(duì)其內(nèi)容進(jìn)行修改沼沈。
驗(yàn)證:
php有個(gè)函數(shù)memory_get_usage()可以用來(lái)查看PHP所使用的內(nèi)存情況流酬。
如上圖可以看出,前面兩個(gè)打印出來(lái)的內(nèi)存使用情況相差并不大列另,而第三個(gè)則拉開(kāi)了很大的差距芽腾,這是因?yàn)楫?dāng)修改變量$a時(shí),程序?yàn)樽兞?a復(fù)制了一份內(nèi)存用于存儲(chǔ)修改后的值页衙。
三摊滔、變量的引用機(jī)制
我們接著上面的例子,把$b = $a
改為$b = &$a
店乐,結(jié)果分析如下:
從上面可以看出艰躺,三個(gè)打印出來(lái)的內(nèi)存使用情況差別都不大,這就是引用的機(jī)制眨八。上面的情況無(wú)論你是修改$a還是$b腺兴,最后$a和$b都會(huì)變?yōu)樾薷暮蟮闹担绦虿](méi)有為修改后的變量開(kāi)啟新的內(nèi)存空間廉侧。
四页响、從zval變量容器底層去了解引用
眾所周知php的變量都是通過(guò)zend引擎來(lái)處理的篓足,而zval結(jié)構(gòu)體則是管理我們變量的一個(gè)容器,而xdebug_debug_zval函數(shù)則是我們調(diào)試zval結(jié)構(gòu)體的一個(gè)好工具(注意闰蚕,想使用該函數(shù)需要安裝Xdebug插件)栈拖。
使用函數(shù)xdebug_debug_zval()打印出來(lái)的zval結(jié)構(gòu)如下:
<?php
$a = 'aaa';
xdebug_debug_zval('a');
在瀏覽器輸出如下內(nèi)容:
a:
(refcount=1, is_ref=0)string 'aaa' (length=3)
結(jié)構(gòu)說(shuō)明:
1)refcount表示引用計(jì)數(shù),用來(lái)記錄有多少個(gè)變量指向這個(gè)zval容器没陡;
2)is_ref表示是否為引用涩哟,一個(gè)bool型的值;
3)表示數(shù)據(jù)的類(lèi)型盼玄;
4)最后則為它的值贴彼。
注意:當(dāng)refcount為1的時(shí)候,is_ref必須為0强岸。當(dāng)refcount為0的時(shí)候锻弓,該容器會(huì)被刪除掉,釋放空間出來(lái)蝌箍。
如果沒(méi)有安裝Xdebug插件青灼,也可以使用php內(nèi)置函數(shù)debug_zval_dump來(lái)查看refcount的值,不過(guò)看不了其它的妓盲。
五杂拨、unset與引用
當(dāng)一個(gè)變量是使用了引用時(shí),unset函數(shù)只會(huì)刪除引用悯衬,并不會(huì)銷(xiāo)毀內(nèi)存空間弹沽。
由如下分析可以證明:
從上面可以看出,三次打印出來(lái)的內(nèi)存使用情況基本沒(méi)有什么變動(dòng)筋粗。
六策橘、對(duì)象與引用
在PHP中,對(duì)象本身就是引用傳遞娜亿。
驗(yàn)證如下:
分析:
1)當(dāng)定義$a2 = $a1時(shí)丽已,zval結(jié)構(gòu)體的refcount值由1變?yōu)?;
2)此時(shí)無(wú)論修改的是$a2->type還是$a1->type的值买决,其實(shí)修改的都是同時(shí)一個(gè)空間里的值沛婴;
3)由此可以發(fā)現(xiàn)此時(shí)并沒(méi)有使用到COW機(jī)制;
4)這是因?yàn)檫@種情況下$a1和$a2引用到了同一個(gè)對(duì)象督赤。
七嘁灯、測(cè)試題
1、寫(xiě)出如下程序的輸出結(jié)果
test = 'aaaaaa';
$abc = & $test;
unset($test);
echo $abc;
// 結(jié)果:aaaaaa
2躲舌、寫(xiě)出如下程序的輸出結(jié)果
$data = ['a', 'b', 'c'];
foreach($data as $k => $v){
$v = &$data[$k];
var_dump($data);
}
var_dump($data);
//程序運(yùn)行時(shí)丑婿,每一次循環(huán)結(jié)束后變量$data的值是什么?
//程序執(zhí)行完后,變量$data的值是什么羹奉?
//請(qǐng)解釋
運(yùn)行結(jié)果如下:
八毅贮、參考文獻(xiàn)
1、Xdebug
官方手冊(cè):https://xdebug.org/docs/all
2尘奏、垃圾回收機(jī)制
關(guān)于PHP垃圾回收機(jī)制(Garbage Collection . GC),這位作者寫(xiě)了三篇比較好的文章病蛉,其中第一篇主要就是講解PHP如何處理變量的炫加。
1) Collecting Garbage: PHP's take on variables
2)Collecting Garbage: Cleaning Up
3)Collecting Garbage: Performance Considerations
第一篇的譯文: https://blog.csdn.net/newbird105/article/details/45315429
3、關(guān)于COW
1)CSDN博客文章:php中COW機(jī)制