php變數的引用賦值與傳值賦值的詳細介紹(代碼)

來源:互聯網
上載者:User
本篇文章給大家帶來的內容是關於php變數的引用賦值與傳值賦值的詳細介紹(代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所協助。

一、使用 memory_get_usage() 查看PHP記憶體使用量量

1. 傳值賦值

// 定義一個變數$a = range(0, 10000);var_dump(memory_get_usage());// 定義變數b,將a變數的值賦值給b$b = $a;var_dump(memory_get_usage());// 對a進行修改// COW: Copy-On-Write$a = range(0, 10000);var_dump(memory_get_usage());

輸出結果:

int(989768)int(989856)int(1855608)

定義一個變數 $a = range(0, 10000);

$b = $a;

對a進行修改 $a = range(0, 10000);

PHP寫時複製機制(Copy-on-Write,也縮寫為COW)

顧名思義,就是在寫入時才真正複製一份記憶體進行修改。
COW最早應用在Unix系統中對線程與記憶體使用量的最佳化,後面廣泛的被使用在各種程式設計語言中,如C++的STL等。
在PHP核心中,COW也是主要的記憶體最佳化手段。
在通過變數賦值的方式賦值給變數時,不會申請新記憶體來存放新變數的值,而是簡單的通過一個計數器來共用記憶體。只有在其中的一個引用指向變數的值發生變化時,才申請新空間來儲存值內容,以減少對記憶體的佔用。
在很多情境下PHP都使用COW進行記憶體的最佳化。比如:變數的多次賦值、函數參數傳遞,並在函數體內修改實參等。

2. 引用賦值

// 定義一個變數$a = range(0, 10000);var_dump(memory_get_usage());// 定義變數b,將a變數的引用賦給b$b = &$a;var_dump(memory_get_usage());// 對a進行修改$a = range(0, 10000);var_dump(memory_get_usage());

輸出結果:

int(989760)int(989848)int(989840)

定義一個變數 $a = range(0, 10000);

定義變數b,將a變數的引用賦給b $b = &$a;

對a進行修改 $a = range(0, 10000);

二、使用 xdebug_debug_zval() 查看變數的引用情況

xdebug_debug_zval() 用於顯示變數的資訊。需要安裝xdebug擴充。

1. 傳值賦值

$a = 1;xdebug_debug_zval('a');// 定義變數b,把a的值賦值給b$b = $a;xdebug_debug_zval('a');xdebug_debug_zval('b');// a進行寫操作$a = 2;xdebug_debug_zval('a');xdebug_debug_zval('b');

輸出結果:

a: (refcount=1, is_ref=0)=1a: (refcount=2, is_ref=0)=1b: (refcount=2, is_ref=0)=1a: (refcount=1, is_ref=0)=2b: (refcount=1, is_ref=0)=1

定義變數 $a = 1;

$a = 1;xdebug_debug_zval('a');

輸出

a: (refcount=1, is_ref=0)=1

refcount=1 表示該變數指向的記憶體位址的引用個數變為1
is_ref=0 表示該變數不是引用

定義變數 $b ,把 $a 的值賦給 $b$b = $a;

$b = $a;xdebug_debug_zval('a');xdebug_debug_zval('b');

輸出

a: (refcount=2, is_ref=0)=1b: (refcount=2, is_ref=0)=1

refcount=2 表示該變數指向的記憶體位址的引用個數變為2
is_ref=0 表示該變數不是引用

對變數 $a 進行寫操作 $a = 2;

$a = 2;xdebug_debug_zval('a');xdebug_debug_zval('b');

輸出

a: (refcount=1, is_ref=0)=2b: (refcount=1, is_ref=0)=1

因為COW機制,對變數 $a 進行寫操作時,會為變數 $a 新分配一塊記憶體空間,用於儲存變數 $a 的值。
此時 $a$b 指向的記憶體位址的引用個數都變為1。

2. 引用賦值

$a = 1;xdebug_debug_zval('a');// 定義變數b,把a的引用賦給b$b = &$a;xdebug_debug_zval('a');xdebug_debug_zval('b');// a進行寫操作$a = 2;xdebug_debug_zval('a');xdebug_debug_zval('b');
a: (refcount=1, is_ref=0)=1a: (refcount=2, is_ref=1)=1b: (refcount=2, is_ref=1)=1a: (refcount=2, is_ref=1)=2b: (refcount=2, is_ref=1)=2

定義變數 $a = 1;

$a = 1;xdebug_debug_zval('a');

輸出

a: (refcount=1, is_ref=0)=1

refcount=1 表示該變數指向的記憶體位址的引用個數變為1
is_ref=0 表示該變數不是引用

定義變數 $b ,把 $a 的引用賦給 $b$b = &$a;

$b = &$a;xdebug_debug_zval('a');xdebug_debug_zval('b');

輸出

a: (refcount=2, is_ref=1)=1b: (refcount=2, is_ref=1)=1

refcount=2 表示該變數指向的記憶體位址的引用個數變為2
is_ref=1 表示該變數是引用

對變數 $a 進行寫操作 $a = 2;

$a = 2;xdebug_debug_zval('a');xdebug_debug_zval('b');

輸出

a: (refcount=2, is_ref=1)=2b: (refcount=2, is_ref=1)=2

因為變數 $a 和變數 $b 指向相同的記憶體位址,其實引用。
對變數 $a 進行寫操作時,會直接修改指向的記憶體空間的值,因此變數 $b 的值會跟著一起改變。

三、當變數時引用時,unset()只會取值 (Dereference),不會銷毀記憶體空間

$a = 1;$b = &$a;// unset 只會取值 (Dereference),不會銷毀記憶體空間unset($b);echo $a;

輸出

1

定義變數 $a ,並將 $a 的引用賦給變數 $b

$a = 1;$b = &$a;

銷毀 $b

unset($b);

輸出 $a

雖然銷毀的 $b,但是 $a 的引用和記憶體空間依舊存在。

echo $a;

輸出

1

四、php中對象本身就是引用賦值

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 }

執行個體化對象 $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 表示該變數指向的記憶體位址的引用個數變為1
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 表示該變數指向的記憶體位址的引用個數變為2

$p2 中的屬性 age 進行寫操作

$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 }

因為php中對象本身就是引用賦值。對 $p2 中的屬性 age 進行寫操作時,會直接修改指向的記憶體空間的值,因此變數 $p1age 屬性的值會跟著一起改變。

五、實戰例題分析

/** * 寫出如下程式的輸出結果 * * $d = ['a', 'b', 'c']; * * foreach($d as $k => $v) * { *    $v = &$d[$k]; * } *  * 程式運行時,每一次迴圈結束後變數 $d 的值是什嗎?請解釋。 * 程式執行完成後,變數 $d 的值是什嗎?請解釋。 */

1. 第一次迴圈

推算出進入 foreach$v$d[$k] 的值

$k = 0$v = 'a'$d[$k] = $d[0] = 'a'

此時,$v$d[0] 在記憶體中分別開闢了一塊空間

![$v 和 $d[0] 在記憶體中分別開闢了一塊空間](http://md.ws65535.top/xsj/201...

$v = &$d[0] 改變了 $v 指向的記憶體位址

$v = &$d[0]

![$v = &$d[0] 改變了 $val 指向的記憶體位址](http://md.ws65535.top/xsj/201...

第一次迴圈後 $d 的值:

['a', 'b', 'c']

2. 第二次迴圈

進入 foreach$v 被賦值為 'b',此時$v指向的記憶體位址與 $d[0] 相同,且為引用,因此 $d[0] 的值被修改為 'b'

$v = 'b' => $d[0] = 'b'

![$v = ‘b’ => $d[0] = ‘b’](http://md.ws65535.top/xsj/201...

推算出進入 foreach$d[$k] 的值

$k = 1$d[$k] = $d[1] = 'b'

![$d[2] = ‘b’](http://md.ws65535.top/xsj/201...

$v = &$d[1] 改變了 $v 指向的記憶體位址

$v = &$d[1]

![$v = &$d[1]](http://md.ws65535.top/xsj/201...

第二次迴圈後 $d 的值

['b', 'b', 'c']

3. 第三次迴圈

進入 foreach$v 被賦值為 'c',此時$v指向的記憶體位址與 $d[1] 相同,且為引用,因此 $d[1] 的值被修改為 'c'

$v = 'c' => $d[1] = 'c'

![$v = ‘c’ => $d[1] = ‘c’](http://md.ws65535.top/xsj/201...

推算出進入 foreach$d[$k] 的值

$k = 2$d[2] = 'c'

![$d[2] = ‘c’](http://md.ws65535.top/xsj/201...

$v = &$d[2] 改變了 $v 指向的記憶體位址

$v = &$d[2]

![$v = &$d[2]](http://md.ws65535.top/xsj/201...

第三次迴圈後 $d 的值

['b', 'c', 'c']

4. 實測

$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)
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.