PHP變量 之 對象類型變量

在 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_2name 也發生的改變,緣由是 obj_1obj_2 指向同一個對象 #1 ,由於在第二行中,咱們將 obj_1 所指向的對象的地址賦給了 obj_2ip

傳遞參數

咱們來看這段代碼:內存

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

  1. 我將 person 對象的引用地址傳遞給 obj參數
  2. 在函數內部第一行,根據 obj 的引用地址,我將函數外部對象的 name 屬性設置成了 "Xavier"
  3. 在第二行,我將一個新的對象賦給了 obj ,既然 obj 爲函數外部對象的引用,那麼外部對象也必定變爲了這個新的對象
  4. 而後我再給這個新的對象設置新的 name 屬性 "zhao" ,嗯,這樣外部對象的 name 必定也變成了 "zhao"

若是你想的和上方相同,那可就大錯特錯了,緣由在於對傳遞參數的過程的錯誤理解。變量

首先,咱們應該明白,將一個變量做爲參數傳遞給函數 能夠理解爲 將那個變量保存的值 複製一份給 函數的參數(參數即函數範圍的局部變量) 。當函數執行時,外部變量函數參數(局部變量) 是同時存在於內存中的,而且二者是相互獨立的,雖然二者所保存的值是相同的;函數參數(局部變量) 會在函數執行完畢後被銷燬。原理

明白了上述原理,那麼咱們從新來看那段代碼:

  1. 函數的 obj 變量在函數內第一行保存的是函數外部 person 變量所保存的值,也就是外部對象的地址
  2. 但到了第二行,obj 變量所保存的值變成了新建立的對象的地址,obj 的指向發生了改變,而原來的外部對象依舊存在而且只被 person 一個變量引用,因此在第三行的行爲並無影響到 person 所指向的那個對象。新建立的對象在函數執行以後被銷燬。

因此有代碼中註釋的輸出結果。

相關文章
相關標籤/搜索