在 PHP 和 JavaScript 中(或許還有其餘語言),變量內所保存的值分爲 基本類型值
和 引用類型值
。函數
$obj = new stdClass;
若一個變量是一個對象,那麼該變量保存的就是一個引用類型的值,即變量中實際保存的是堆內存中對象的地址,而不是對象的實體;若變量爲其餘類型,則保存的是基本類型值,而不是引用地址。這一點須要特別注意,由於咱們可能會遇到以下幾種狀況,不清楚原理可能致使出錯。code
$obj_1 = new stdClass; $obj_2 = $obj_1; $obj_1->name = 'Xavier'; var_dump($obj_1->name, $obj_2->name); var_dump($obj_1, $obj_2);
輸出:對象
string(6) "Xavier" string(6) "Xavier" object(stdClass)#1 (1) { ["name"]=> string(6) "Xavier" } object(stdClass)#1 (1) { ["name"]=> string(6) "Xavier" }
咱們發現 obj_2
的 name
也發生的改變,緣由是 obj_1
和 obj_2
指向同一個對象 #1
,由於在第二行中,咱們將 obj_1
所指向的對象的地址賦給了 obj_2
。ip
咱們來看這段代碼:內存
function setName($obj) { $obj->name = 'Xavier'; } $person = new stdClass; setName($person); var_dump($person->name); // 輸出 string(6) "Xavier"
若變量爲一個對象,那麼當它做爲參數傳遞給一個函數時,一樣,傳遞的是一個對象地址,而不是拷貝了一個新的對象實體給參數 $obj
。這樣,函數內部並無 return 新的東西出來但改變了外部的狀態
的這種狀況就變得好理解了。string
接下來,請看這段代碼:io
function setName($obj) { $obj->name = 'Xavier'; $obj = new stdClass; $obj->name = 'Zhao'; } $person = new stdClass; setName($person); var_dump($person->name); // 輸出了 string(6) "Xavier" 而不是 string(6) "Zhao"
最後的輸出結果可能會讓不少人會疑惑,他們的思惟多是這樣的:function
person
對象的引用地址傳遞給 obj參數
obj
的引用地址,我將函數外部對象的 name
屬性設置成了 "Xavier"
obj
,既然 obj
爲函數外部對象的引用,那麼外部對象也必定變爲了這個新的對象name
屬性 "zhao"
,嗯,這樣外部對象的 name
必定也變成了 "zhao"
若是你想的和上方相同,那可就大錯特錯了,緣由在於對傳遞參數的過程的錯誤理解。變量
首先,咱們應該明白,將一個變量做爲參數傳遞給函數
能夠理解爲 將那個變量保存的值 複製一份給 函數的參數(參數即函數範圍的局部變量)
。當函數執行時,外部變量
和 函數參數(局部變量)
是同時存在於內存中的,而且二者是相互獨立的,雖然二者所保存的值是相同的;函數參數(局部變量)
會在函數執行完畢後被銷燬。原理
明白了上述原理,那麼咱們從新來看那段代碼:
obj
變量在函數內第一行保存的是函數外部 person
變量所保存的值,也就是外部對象的地址obj
變量所保存的值變成了新建立的對象的地址,obj
的指向發生了改變,而原來的外部對象依舊存在而且只被 person
一個變量引用,因此在第三行的行爲並無影響到 person
所指向的那個對象。新建立的對象在函數執行以後被銷燬。因此有代碼中註釋的輸出結果。