深入理解PHP中賦值與引用

2022-02-15 14:39:54 字數 1868 閱讀 9413

先看下面的問題:

<?php 

$a = 10;//將常量值賦給變數,會為a分配記憶體空間

$b = $a;//變數賦值給變數,是不是copy了乙份副本,b也分配了記憶體空間呢?

$c = &$a;//引用是不會為c分配空間的,c和a是共用乙份空間的。

?>

對於中間的那個問題,你的答案是什麼呢?在今天之前,我的答案是會為b分配記憶體空間。因為我是這麼理解的:

&賦值的時候,視為乙個變數定義了乙個別名,增加了乙個對記憶體空間的引用。改變其中乙個,會影響其他的引用。而使用unset()時,只是斷開了對變數記憶體空間的引用,記憶體空間不會釋放。

而 = 賦值則不同,它會重新開闢乙份記憶體空間儲存原變數的副本。兩者之間的修改不會相互影響。

而下面的程式則印證了這一點:

<?php 

$a = 10;//將常量值賦給變數,會為a分配記憶體空間

$b = $a;//變數賦值給變數,是不是copy了乙份副本,b也分配了記憶體空間呢?

$c = &$a;//引用是不會為c分配空間的,c和a是共用乙份空間的。

$a = 5;

echo $c;//輸出5,因為a和c 是指向同乙個記憶體空間

echo php_eol;

echo $b;//由於b是副本,對a的操作不會影響b,輸出10

?>

那如果  

$b = $a;//之後a  和  b 都不做任何改變,保持一致

有這麼乙個問題,如果 = 賦值之後,兩個變數都不曾改變,如果是兩份副本,豈不是太浪費記憶體?

php中實際上避免了這種情況。

php中將乙個變數賦值給新變數時,不會立即為新變數分配記憶體空間,只是增加了對記憶體空間的引用。當原變數或者新變數作出任何改變時,才會為新變數 分配一塊記憶體空間。

<?php 

$a = 1;

$b = $a;

echo $a;

//在此之前,b都是和a共用記憶體空間的。

$a = 2;//a作出了改變,此時b才會有自己的空間

?>

每個php變數存在乙個叫"zval"的變數容器中。乙個zval變數容器,除了包含變數的型別和值,還包括兩個位元組的額外資訊。第乙個是"is_ref",是個bool值,用來標識這個變數是否是屬於引用集合(referenceset)。通過這個位元組,php引擎才能把普通變數和引用變數區分開來,由於php允許使用者通過使用&來使用自定義引用,zval變數容器中還有乙個內部引用計數機制,來優化記憶體使用。第二個額外位元組是"refcount",用以表示指向這個zval變數容器的變數(也稱符號即symbol)個數。當"refcount"的值是1時,"is_ref"的值總是false

安裝xdebug之後,利用xdebug_debug_zval(),可以看到zval結構:

如下:

<?php 

$a = 1;

$b = $a;

echo $a;

//在此之前,b都是和a共用記憶體空間的。

xdebug_debug_zval('b');

$a = 2;//a作出了改變,此時b才會有自己的空間

xdebug_debug_zval('b');

?>

輸出:b:

(refcount=2, is_ref=0),
int 

1
b:

(refcount=1, is_ref=0),
int 

1
由上面的結果可以看到,在a作出改變之前,引用計數是2 ,當a作出改變之後,b的引用計數變為1,是因為b重新分配了空間

深入理解php的引用賦值

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

深入理解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 宣告...