1. 程式人生 > >淺談PHP值傳遞與值引用

淺談PHP值傳遞與值引用

PHP傳值和傳引用、傳地址的區別是什麼?

傳值:

是把實參的值賦值給形參,那麼對形參的修改,不會影響實參的值


傳地址:

是傳值的一種特殊方式,只是他傳遞的是地址,不是普通的如int
那麼傳地址以後,實參和形參都指向同一個物件

傳引用:

真正的以地址的方式傳遞引數
傳遞以後,形參和實參都是同一個物件,只是他們名字不同而已
對形參的修改將影響實參的值

從函式呼叫的角度理解比較好

傳值:
函式引數壓棧的是引數的副本,任何的修改是在副本上作用,沒有作用在原來的變數上。


傳指標:
壓棧的是指標變數的副本。
當你對指標解指標操作時,其值是指向原來的那個變數,所以對原來變數操作。

傳引用:
壓棧的是引用的副本。由於引用是指向某個變數的,對引用的操作其實就是對他指向的變數的操作。(作用和傳指標一樣,只是引用少了解指標的草紙)  

函式引數傳遞機制的基本理論


函式引數傳遞機制問題在本質上是呼叫函式(過程)和被呼叫函式(過程)在呼叫發生時進行通訊的方法問題;函式的目的終歸是對目標資料的處理(常見的有,設定變數的值等其它屬性)。

基本的引數傳遞機制有兩種:值傳遞和引用傳遞。

以下討論稱呼叫其他函式的函式為主調函式,被呼叫的函式為被調函式:
     

值傳遞(passl-by-value)過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的一個副本。值傳遞的特點是被調函式對形式引數的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。(ps:即值傳遞過程中,函式是對作為區域性變數的形參進行的操作!)
     

引用傳遞(pass-by-reference)過程中,被調函式的形式引數雖然也作為區域性變數在堆疊中開闢了記憶體空間,但是這時存放的是由主調函式放進來的實參變數的地址被調函式對形參的任何操作都被處理成間接定址,即通過堆疊中存放的地址訪問主調函式中的實參變數。正因為如此,被調函式對形參做的任何操作都影響了主調函式中的實參變數。 ps:表面對形參的操作實際是對實參變數的操作。

 如上所述,值傳遞和引用傳遞對實參變數的處理過程是不一樣的,函式對值的操作和對引用的操作的機制是不一樣;形參總是被作為區域性變數來處理的,函式會根據在其記憶體空間中儲存的是實參的值的副本還是實參的地址的副本分別處理,至於函式是如何區分值和地址的,我不得而知,貌似也不必知道。


僅討論一下值傳遞和引用:

所謂值傳遞,就是說僅將物件的值傳遞給目標物件,就相當於copy;系統將為目標物件重新開闢一個完全相同的記憶體空間。
所謂引用,就是說將物件在記憶體中的地址傳遞給目標物件,就相當於使目標物件和原始物件對應同一個記憶體儲存空間。此時,如果對目標物件進行修改,記憶體中的資料也會改變。

引用的作用 
如果程式比較大,引用同一個物件的變數比較多,並且希望用完該物件後手工清除它,個人建議用 "&" 方式,然後用$var=null的方式清除. 其它時候還是用php5的預設方式吧. 另外, php5中對於大陣列的傳遞,建議用 "&" 方式, 畢竟節省記憶體空間使用。

取消引用 
當你 unset 一個引用,只是斷開了變數名和變數內容之間的繫結。這並不意味著變數內容被銷燬了。例如:

<?php 
$a = 1; 
$b =& $a; 
unset ($a); 
?>

不會 unset $b,只是 $a。

global 引用 
當用 global $var 宣告一個變數時實際上建立了一個到全域性變數的引用。也就是說和這樣做是相同的:

<?php 
$var =& $GLOBALS["var"]; 
?>

這意味著,例如,unset $var 不會 unset 全域性變數。

$this 
在一個物件的方法中,$this 永遠是呼叫它的物件的引用。

補充:
php中對於地址的指向(類似指標)功能不是由使用者自己來實現的,是由Zend核心實現的,php中引用採用的是“寫時拷貝”的原理,就是除非發生寫操作,指向同一個地址的變數或者物件是不會被拷貝的。