国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

搞定PHP面試 - 變量的引用賦值與傳值賦值

liangdas / 2561人閱讀

摘要:比如變量的多次賦值函數(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í)參等。

2. 引用賦值
// 定義一個(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 的值賦給 $b$b = $a;
$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 表示該變量不是引用

對(duì)變量 $a 進(jìn)行寫操作 $a = 2;
$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)?。

2. 引用賦值
$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 的引用賦給 $b$b = &$a;
$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 表示該變量是引用

對(duì)變量 $a 進(jìn)行寫操作 $a = 2;
$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ì)跟著一起改變。

三、當(dāng)變量時(shí)引用時(shí),unset()只會(huì)取消引用,不會(huì)銷毀內(nèi)存空間
$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 表示該變量不是引用

$p1 賦給 $p2
$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)存空間的值,因此變量 $p1age 屬性的值會(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

相關(guān)文章

  • 搞定PHP面試 - 變量知識(shí)點(diǎn)整理

    摘要:聲明靜態(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; /...

    Mertens 評(píng)論0 收藏0
  • 搞定PHP面試 - 深入了解引用

    摘要:引用可以被看作是文件系統(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 的文件名和...

    fox_soyoung 評(píng)論0 收藏0
  • 一篇文章理解JS數(shù)據(jù)類型、深拷貝和淺拷貝

    摘要:接下來(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...

    EddieChan 評(píng)論0 收藏0
  • 一篇文章理解JS數(shù)據(jù)類型、深拷貝和淺拷貝

    摘要:接下來(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...

    enda 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<