摘要:比如變量的多次賦值函數(shù)參數(shù)傳遞,并在函數(shù)體內(nèi)修改實(shí)參等。引用賦值定義一個(gè)變量定義變量,將變量的引用賦給對(duì)進(jìn)行修改輸出結(jié)果定義一個(gè)變量定義變量,將變量的引用賦給對(duì)進(jìn)行修改二使用查看變量的引用情況用于顯示變量的信息。
一、使用 memory_get_usage() 查看PHP內(nèi)存使用量 1. 傳值賦值
// 定義一個(gè)變量 $a = range(0, 10000); var_dump(memory_get_usage()); // 定義變量b,將a變量的值賦值給b $b = $a; var_dump(memory_get_usage()); // 對(duì)a進(jìn)行修改 // COW: Copy-On-Write $a = range(0, 10000); var_dump(memory_get_usage());
輸出結(jié)果:
int(989768) int(989856) int(1855608)定義一個(gè)變量 $a = range(0, 10000); $b = $a; 對(duì)a進(jìn)行修改 $a = range(0, 10000);
PHP寫時(shí)復(fù)制機(jī)制(Copy-on-Write,也縮寫為COW)
顧名思義,就是在寫入時(shí)才真正復(fù)制一份內(nèi)存進(jìn)行修改。
COW最早應(yīng)用在Unix系統(tǒng)中對(duì)線程與內(nèi)存使用的優(yōu)化,后面廣泛的被使用在各種編程語(yǔ)言中,如C++的STL等。
在PHP內(nèi)核中,COW也是主要的內(nèi)存優(yōu)化手段。
在通過(guò)變量賦值的方式賦值給變量時(shí),不會(huì)申請(qǐng)新內(nèi)存來(lái)存放新變量的值,而是簡(jiǎn)單的通過(guò)一個(gè)計(jì)數(shù)器來(lái)共用內(nèi)存。只有在其中的一個(gè)引用指向變量的值發(fā)生變化時(shí),才申請(qǐng)新空間來(lái)保存值內(nèi)容,以減少對(duì)內(nèi)存的占用。
在很多場(chǎng)景下PHP都使用COW進(jìn)行內(nèi)存的優(yōu)化。比如:變量的多次賦值、函數(shù)參數(shù)傳遞,并在函數(shù)體內(nèi)修改實(shí)參等。
// 定義一個(gè)變量 $a = range(0, 10000); var_dump(memory_get_usage()); // 定義變量b,將a變量的引用賦給b $b = &$a; var_dump(memory_get_usage()); // 對(duì)a進(jìn)行修改 $a = range(0, 10000); var_dump(memory_get_usage());
輸出結(jié)果:
int(989760) int(989848) int(989840)定義一個(gè)變量 $a = range(0, 10000); 定義變量b,將a變量的引用賦給b $b = &$a; 對(duì)a進(jìn)行修改 $a = range(0, 10000); 二、使用 xdebug_debug_zval() 查看變量的引用情況
xdebug_debug_zval() 用于顯示變量的信息。需要安裝xdebug擴(kuò)展。1. 傳值賦值
$a = 1; xdebug_debug_zval("a"); // 定義變量b,把a(bǔ)的值賦值給b $b = $a; xdebug_debug_zval("a"); xdebug_debug_zval("b"); // a進(jìn)行寫操作 $a = 2; xdebug_debug_zval("a"); xdebug_debug_zval("b");
輸出結(jié)果:
a: (refcount=1, is_ref=0)=1 a: (refcount=2, is_ref=0)=1 b: (refcount=2, is_ref=0)=1 a: (refcount=1, is_ref=0)=2 b: (refcount=1, is_ref=0)=1定義變量 $a = 1;
$a = 1; xdebug_debug_zval("a");
輸出
a: (refcount=1, is_ref=0)=1
refcount=1 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
is_ref=0 表示該變量不是引用
$b = $a; xdebug_debug_zval("a"); xdebug_debug_zval("b");
輸出
a: (refcount=2, is_ref=0)=1 b: (refcount=2, is_ref=0)=1
refcount=2 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
is_ref=0 表示該變量不是引用
$a = 2; xdebug_debug_zval("a"); xdebug_debug_zval("b");
輸出
a: (refcount=1, is_ref=0)=2 b: (refcount=1, is_ref=0)=1
因?yàn)镃OW機(jī)制,對(duì)變量 $a 進(jìn)行寫操作時(shí),會(huì)為變量 $a 新分配一塊內(nèi)存空間,用于存儲(chǔ)變量 $a 的值。
此時(shí) $a 和 $b 指向的內(nèi)存地址的引用個(gè)數(shù)都變?yōu)?。
$a = 1; xdebug_debug_zval("a"); // 定義變量b,把a(bǔ)的引用賦給b $b = &$a; xdebug_debug_zval("a"); xdebug_debug_zval("b"); // a進(jìn)行寫操作 $a = 2; xdebug_debug_zval("a"); xdebug_debug_zval("b");
a: (refcount=1, is_ref=0)=1 a: (refcount=2, is_ref=1)=1 b: (refcount=2, is_ref=1)=1 a: (refcount=2, is_ref=1)=2 b: (refcount=2, is_ref=1)=2定義變量 $a = 1;
$a = 1; xdebug_debug_zval("a");
輸出
a: (refcount=1, is_ref=0)=1
refcount=1 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
is_ref=0 表示該變量不是引用
$b = &$a; xdebug_debug_zval("a"); xdebug_debug_zval("b");
輸出
a: (refcount=2, is_ref=1)=1 b: (refcount=2, is_ref=1)=1
refcount=2 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
is_ref=1 表示該變量是引用
$a = 2; xdebug_debug_zval("a"); xdebug_debug_zval("b");
輸出
a: (refcount=2, is_ref=1)=2 b: (refcount=2, is_ref=1)=2
因?yàn)樽兞?$a 和變量 $b 指向相同的內(nèi)存地址,其實(shí)引用。
對(duì)變量 $a 進(jìn)行寫操作時(shí),會(huì)直接修改指向的內(nèi)存空間的值,因此變量 $b 的值會(huì)跟著一起改變。
$a = 1; $b = &$a; // unset 只會(huì)取消引用,不會(huì)銷毀內(nèi)存空間 unset($b); echo $a;
輸出
1定義變量 $a ,并將 $a 的引用賦給變量 $b
$a = 1; $b = &$a;銷毀 $b
unset($b);輸出 $a
雖然銷毀的 $b,但是 $a 的引用和內(nèi)存空間依舊存在。
echo $a;
輸出
1四、php中對(duì)象本身就是引用賦值
class Person { public $age = 1; } $p1 = new Person; xdebug_debug_zval("p1"); $p2 = $p1; xdebug_debug_zval("p1"); xdebug_debug_zval("p2"); $p2->age = 2; xdebug_debug_zval("p1"); xdebug_debug_zval("p2");
p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 } p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 } p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 } p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 } p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }實(shí)例化對(duì)象 $p1 = new Person;
$p1 = new Person; xdebug_debug_zval("p1");
輸出
p1: (refcount=1, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
refcount=1 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
is_ref=0 表示該變量不是引用
$p2 = $p1; xdebug_debug_zval("p1"); xdebug_debug_zval("p2");
輸出
p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 } p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=2, is_ref=0)=1 }
refcount=2 表示該變量指向的內(nèi)存地址的引用個(gè)數(shù)變?yōu)?
對(duì) $p2 中的屬性 age 進(jìn)行寫操作$p2->age = 2; xdebug_debug_zval("p1"); xdebug_debug_zval("p2");
輸出
p1: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 } p2: (refcount=2, is_ref=0)=class Person { public $age = (refcount=1, is_ref=0)=2 }
因?yàn)閜hp中對(duì)象本身就是引用賦值。對(duì) $p2 中的屬性 age 進(jìn)行寫操作時(shí),會(huì)直接修改指向的內(nèi)存空間的值,因此變量 $p1 的 age 屬性的值會(huì)跟著一起改變。
五、實(shí)戰(zhàn)例題分析/** * 寫出如下程序的輸出結(jié)果 * * $d = ["a", "b", "c"]; * * foreach($d as $k => $v) * { * $v = &$d[$k]; * } * * 程序運(yùn)行時(shí),每一次循環(huán)結(jié)束后變量 $d 的值是什么?請(qǐng)解釋。 * 程序執(zhí)行完成后,變量 $d 的值是什么?請(qǐng)解釋。 */1. 第一次循環(huán) 推算出進(jìn)入 foreach 時(shí) $v、$d[$k] 的值
$k = 0 $v = "a" $d[$k] = $d[0] = "a"
此時(shí),$v 和 $d[0] 在內(nèi)存中分別開(kāi)辟了一塊空間
![$v 和 $d[0] 在內(nèi)存中分別開(kāi)辟了一塊空間](http://md.ws65535.top/xsj/201...
$v = &$d[0] 改變了 $v 指向的內(nèi)存地址$v = &$d[0]
![$v = &$d[0] 改變了 $val 指向的內(nèi)存地址](http://md.ws65535.top/xsj/201...
第一次循環(huán)后 $d 的值:["a", "b", "c"]2. 第二次循環(huán) 進(jìn)入 foreach 時(shí) $v 被賦值為 "b",此時(shí)$v指向的內(nèi)存地址與 $d[0] 相同,且為引用,因此 $d[0] 的值被修改為 "b"
$v = "b" => $d[0] = "b"
![$v = ‘b’ => $d[0] = ‘b’](http://md.ws65535.top/xsj/201...
推算出進(jìn)入 foreach 時(shí) $d[$k] 的值$k = 1 $d[$k] = $d[1] = "b"
![$d[2] = ‘b’](http://md.ws65535.top/xsj/201...
$v = &$d[1] 改變了 $v 指向的內(nèi)存地址$v = &$d[1]
![$v = &$d[1]](http://md.ws65535.top/xsj/201...
第二次循環(huán)后 $d 的值["b", "b", "c"]3. 第三次循環(huán) 進(jìn)入 foreach 時(shí) $v 被賦值為 "c",此時(shí)$v指向的內(nèi)存地址與 $d[1] 相同,且為引用,因此 $d[1] 的值被修改為 "c"
$v = "c" => $d[1] = "c"
![$v = ‘c’ => $d[1] = ‘c’](http://md.ws65535.top/xsj/201...
推算出進(jìn)入 foreach 時(shí) $d[$k] 的值$k = 2 $d[2] = "c"
![$d[2] = ‘c’](http://md.ws65535.top/xsj/201...
$v = &$d[2] 改變了 $v 指向的內(nèi)存地址$v = &$d[2]
![$v = &$d[2]](http://md.ws65535.top/xsj/201...
第三次循環(huán)后 $d 的值["b", "c", "c"]4. 實(shí)測(cè)
$d = ["a", "b", "c"]; foreach ($d as $k=>$v) { $v = &$d[$k]; print_r($d); } print_r($d);輸出:
Array ( [0] => a [1] => b [2] => c ) Array ( [0] => b [1] => b [2] => c ) Array ( [0] => b [1] => c [2] => c ) Array ( [0] => b [1] => c [2] => c )
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/29360.html
摘要:聲明靜態(tài)變量時(shí)不能用表達(dá)式的結(jié)果對(duì)其賦值正確錯(cuò)誤使用表達(dá)式的結(jié)果賦值錯(cuò)誤使用表達(dá)式的結(jié)果賦值靜態(tài)變量與遞歸函數(shù)靜態(tài)變量提供了一種處理遞歸函數(shù)的方法。 一、變量的定義 1. 變量的命名規(guī)則 變量名可以包含字母、數(shù)字、下劃線,不能以數(shù)字開(kāi)頭。 $Var_1 = foo; // 合法 $var1 = foo; // 合法 $_var1 = foo; // 合法 $Var-1 = foo; /...
摘要:引用可以被看作是文件系統(tǒng)中的硬鏈接。如果具有引用的數(shù)組被復(fù)制,其值不會(huì)解除引用。如果試圖這樣從函數(shù)返回引用,將會(huì)報(bào)錯(cuò),因?yàn)楹瘮?shù)在試圖返回一個(gè)表達(dá)式的結(jié)果而不是一個(gè)引用的變量。這并不意味著變量?jī)?nèi)容被銷毀了。 1. 什么是引用 在 PHP 中引用是指用不同的名字訪問(wèn)同一個(gè)變量?jī)?nèi)容。PHP 中的變量名和變量?jī)?nèi)容是不一樣的, 因此同樣的內(nèi)容可以有不同的名字。最接近的比喻是 Unix 的文件名和...
摘要:接下來(lái)我們進(jìn)入正片數(shù)據(jù)類型六種基本數(shù)據(jù)類型布爾值,和一個(gè)表明值的特殊關(guān)鍵字。一種數(shù)據(jù)類型,它的實(shí)例是唯一且不可改變的。在中是沒(méi)有方法是可以改變布爾值和數(shù)字的。參考資料深拷貝淺拷貝 前言 筆者最近整理了一些前端技術(shù)文章,如果有興趣可以參考這里:muwoo blogs。接下來(lái)我們進(jìn)入正片: js 數(shù)據(jù)類型 六種 基本數(shù)據(jù)類型: Boolean. 布爾值,true 和 false. nu...
摘要:接下來(lái)我們進(jìn)入正片數(shù)據(jù)類型六種基本數(shù)據(jù)類型布爾值,和一個(gè)表明值的特殊關(guān)鍵字。一種數(shù)據(jù)類型,它的實(shí)例是唯一且不可改變的。在中是沒(méi)有方法是可以改變布爾值和數(shù)字的。參考資料深拷貝淺拷貝 前言 筆者最近整理了一些前端技術(shù)文章,如果有興趣可以參考這里:muwoo blogs。接下來(lái)我們進(jìn)入正片: js 數(shù)據(jù)類型 六種 基本數(shù)據(jù)類型: Boolean. 布爾值,true 和 false. nu...
閱讀 3241·2021-10-13 09:39
閱讀 2007·2021-09-27 13:36
閱讀 3069·2021-09-22 16:02
閱讀 2593·2021-09-10 10:51
閱讀 1574·2019-08-29 17:15
閱讀 1529·2019-08-29 16:14
閱讀 3495·2019-08-26 11:55
閱讀 2544·2019-08-26 11:50