曾經我一直認為,基礎資料類型都是傳值調用,而具體的類都是傳引用調用,但是,現在我認為
世界上本沒有傳引用調用,所有的函數參數都是傳值調用(除了PHP的&或指標調用)
為什麼這麼說,看代碼
1
$a = 1;test($a);echo $a;function test($a) { $a = 2; }
這個不用我說,輸出的是 1
2
$a = new Man;$a->age = 1;test($a)echo $a->age;class Man { public $age; }function test(Man $a) { $a->age = 2; }
這裡輸出是2, 那他叫傳引用調用嗎
3
$a = new Man;$a->age = 1;test($a);echo $a->age;class Man { public $age; }function test(Man $a) { $a = new Man; $a->age = 2; }
元芳,這段代碼你怎麼看?
答案是 1,這就奇怪了,這裡不是傳引用嗎?
其實不是的,正如我所說,其實所有都是傳值,只不過,這個值是一個類,這個類是個拷貝的,但是拷貝類的內部成員的地址都是原類的成員的真真實位址,而他自己確實是拷貝的,下面我們換一種方法理解
$a = new Man;$a->age = 1;$b = $a;$b->age = 3;echo $a->age;class Man { public $age; }
這裡輸出 3
$a = new Man;$a->age = 1;$b = $a;$b = new Man;$b->age = 3;echo $a->age;class Man { public $age; }
這裡輸出 1
這樣就好理解了,實際上函數的調用傳參和這種賦值是一個道理
當 $b = new Man; 的時候, a的zval就要發生分裂了(參見我之前寫的PHP引用計數)
而 如果沒有 $b = new Man; 直接 $b->age = 3,實際上$b->age相當與 &$a->age,也就是說不會發生zval的分裂
結論,類參數傳遞是也是一個普通的值(拷貝)傳遞,只不過類拷貝的成員變數都是源類的成員變數的引用,所以你直接修改類如
function test(Man $a) {
$a = new Man;
}
是不會有任何效果的,當然強制引用傳遞和指標除外,例如下面的
function test(Man &$a) {
$a = new Man;
}
The End