深入理解php的引用賦值

2021-06-14 12:50:52 字數 3276 閱讀 4047

關於php引用的一般問題大家看資料就行了,這次我們來聊點有趣的東西。今天乙個朋友在群裡面問起來乙個關於變數引用賦值的問題,問題本身很簡單,我突然想做乙個實驗,來看看array直接賦值和引用賦值效能上的差別,寫完**發現另外乙個問題.請看**

<?php

$a = array_fill(0, 1000000, 10);

function test_time_cost($loop, $func) ;

function fetch_data($b) {}

test_time_cost(10000, function() );

test_time_cost(10000, function() );

**在第二個測試函式裡出錯了,記憶體不夠了。但是問題是php在變數賦值以後,如果目標變數未被使用,是不會執行賦值操作的。因為php語言在處理變數賦值時實際上是給$a和$b開闢了乙個變數容器,在容器裡$a和$b是對等的,可以簡單理解為引用關係。但是當$b被改動時,$b就會被移出容器。

<?php

$a = array_fill(0, 1000000, 10);

$b = $a; // 記憶體不增加

$b[0] = 10; // $a所佔記憶體會賦值給$b

fetch_data函式實際上未對變數做任何處理,怎麼會觸發複製呢?於是我寫了下面的**

<?php

echo "memory_limit = " . ini_get('memory_limit') ."\n";

echo "memory init = " . memory_get_usage(true) . "\n";

$a = array_fill(0, 10000, 10);

echo "memory after a = " . memory_get_usage(true) ."\n";

$c = $b = $a;

echo "memory after c,b = " . memory_get_usage(true) ."\n";

function fetch_data($m)

fetch_data($a);

global $a; fetch_data($a);

執行結果如下

memory_limit = 128m

memory init = 786432

memory after a = 1835008

memory after c,b = 1835008

memory in fetch_data = 1835008

memory in fetch_data = 3670016

說明在宣告global $a以後發生了變數拷貝賦值,既然是這樣,看看php的文件吧,是不是對global申明的變數有什麼特殊處理。看了一遍,沒什麼特殊的,就是建立引用物件。於是我又仔細看了一次php關於引用的說明, 我這次準備跟蹤一下引用計數器

$a = array_fill(0, 1, 10);

$c = $b = $a;

echo "c,b,a\n";

xdebug_debug_zval('a');

xdebug_debug_zval('b');

xdebug_debug_zval('c');

echo "changing b\n";

$b[0] = 8;

xdebug_debug_zval('a');

xdebug_debug_zval('b');

xdebug_debug_zval('c');

echo "global a\n";

global $a;

xdebug_debug_zval('a');

xdebug_debug_zval('b');

xdebug_debug_zval('c');

echo "c,b,global a\n";

$c = $b = $a;

xdebug_debug_zval('a');

xdebug_debug_zval('b');

xdebug_debug_zval('c');

執行的結果

c,b,a

a: (refcount=3, is_ref=0)=array (0 => (refcount=1, is_ref=0)=10)

b: (refcount=3, is_ref=0)=array (0 => (refcount=1, is_ref=0)=10)

c: (refcount=3, is_ref=0)=array (0 => (refcount=1, is_ref=0)=10)

changing b

a: (refcount=2, is_ref=0)=array (0 => (refcount=1, is_ref=0)=10)

b: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)=8)

c: (refcount=2, is_ref=0)=array (0 => (refcount=1, is_ref=0)=10)

global a

a: (refcount=1, is_ref=1)=array (0 => (refcount=2, is_ref=0)=10)

b: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)=8)

c: (refcount=1, is_ref=0)=array (0 => (refcount=2, is_ref=0)=10)

c,b,global a

a: (refcount=1, is_ref=1)=array (0 => (refcount=2, is_ref=0)=10)

b: (refcount=2, is_ref=0)=array (0 => (refcount=2, is_ref=0)=10)

c: (refcount=2, is_ref=0)=array (0 => (refcount=2, is_ref=0)=10)

終於看出了問題,在沒有global $a的時候,a,b,c在同乙個變數容器裡,所以沒有發生複製行為。但是在宣告global $a以後再進行複製,b,c不和a在同一容器了。我覺得原因就在於$a這個時候已經不是簡單的變數了,可以理解為乙個指標。php在這個時候沒有辦法建立變數容器同時給變數和指標,所以拷貝於是就發生了。

深入理解PHP中賦值與引用

先看下面的問題 a 10 將常量值賦給變數,會為a分配記憶體空間 b a 變數賦值給變數,是不是copy了乙份副本,b也分配了記憶體空間呢?c a 引用是不會為c分配空間的,c和a是共用乙份空間的。對於中間的那個問題,你的答案是什麼呢?在今天之前,我的答案是會為b分配記憶體空間。因為我是這麼理解的 ...

深入理解PHP物件賦值

1 2 深入理解php物件賦值 3echo 45 obj new stdclass 6 obj name pig 7var dump obj object stdclass 1 1 89 copy obj obj copy都是new stdclass返回的同乙個識別符號的拷貝 10var dump ...

深入理解 引用

引用簡介 引用就是某一變數 目標 的乙個別名,對引用的操作和對變數直接操作完全相同。引用的宣告方法 型別識別符號 引用名 目標變數名 例1 int a int ra a 定義引用ra,他是變數a的引用,即別名 說明 1 在此不是求位址運算,而是起標識作用。2 型別識別符號是指目標變數的型別。3 宣告...