在 PHP 和 JavaScript 中(也許另有其他言語),變量內所保留的值分為 基礎範例值
和 援用範例值
。
$obj = new stdClass;
若一個變量是一個對象,那末該變量保留的就是一個援用範例的值,即變量中現實保留的是堆內存中對象的地點,而不是對象的實體;若變量為其他範例,則保留的是基礎範例值,而不是援用地點。這一點須要特別注意,由於我們能夠會碰到以下幾種狀況,不清楚道理能夠致使失足。
賦值
$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
。
通報參數
我們來看這段代碼:
function setName($obj) {
$obj->name = 'Xavier';
}
$person = new stdClass;
setName($person);
var_dump($person->name); // 輸出 string(6) "Xavier"
若變量為一個對象,那末當它作為參數通報給一個函數時,一樣,通報的是一個對象地點,而不是拷貝了一個新的對象實體給參數 $obj
。如許,函數內部並沒有 return 新的東西出來但轉變了外部的狀況
的這類狀況就變得好邃曉了。
接下來,請看這段代碼:
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"
末了的輸出效果能夠會讓很多人會迷惑,他們的頭腦多是如許的:
- 我將
person
對象的援用地點通報給obj參數
- 在函數內部第一行,依據
obj
的援用地點,我將函數外部對象的name
屬性設置成了"Xavier"
- 在第二行,我將一個新的對象賦給了
obj
,既然obj
為函數外部對象的援用,那末外部對象也肯定變為了這個新的對象 - 然後我再給這個新的對象設置新的
name
屬性"zhao"
,嗯,如許外部對象的name
肯定也變成了"zhao"
假如你想的和上方雷同,那可就大錯特錯了,緣由在於對通報參數的歷程的毛病邃曉。
起首,我們應當邃曉,將一個變量作為參數通報給函數
能夠邃曉為 將誰人變量保留的值 複製一份給 函數的參數(參數即函數局限的局部變量)
。當函數實行時,外部變量
和 函數參數(局部變量)
是同時存在於內存中的,而且二者是互相自力的,雖然二者所保留的值是雷同的;函數參數(局部變量)
會在函數實行終了后被燒毀。
邃曉了上述道理,那末我們從新來看那段代碼:
- 函數的
obj
變量在函數內第一行保留的是函數外部person
變量所保留的值,也就是外部對象的地點 - 但到了第二行,
obj
變量所保留的值變成了新創建的對象的地點,obj
的指向發作了轉變,而本來的外部對象照舊存在而且只被person
一個變量援用,所以在第三行的行動並沒有影響到person
所指向的誰人對象。新創建的對象在函數實行以後被燒毀。
所以有代碼中解釋的輸出效果。