首先,要理解變量名存儲在內存棧中,它是指向堆中具體內存的地址,經過變量名查找堆中的內存;
普通傳值,傳值之後,是不一樣的地址名稱,指向不一樣的內存實體;
引用傳值,傳引用後,是不一樣的地址名稱,但都指向同一個內存實體;改變其中一個,另一個就也被改變;php
如下我將經過三個列子來詳細講解這兩個傳值的區別:面試
Example1:數組
<?php //普通傳值 $param1=1; $param2=2; $param2 = $param1; $param1 = 5; //變量1和變量2是兩塊內存,互不影響; echo $param2; //因此此處仍是顯示爲1 //引用傳值 ↓↓ $param1=1; $param2=2; $param2 = &$param1; //把變量1的內存地址賦給變量2;此時的變量2和變量1全等; echo $param2;// 1 $param1 = 5; //變量1和變量2是一處內存,改變其中一個,另一個也被改變; echo $param2; //顯示爲5 ?>
Example2:函數
<?php //函數中的普通傳值 ↓↓ $param1 = 1; function add($param2){ $param2=3; } //調用方法add,並將變量1傳給變量2,此處是普通傳值,因此變量1和變量2是兩處內存,互不影響; $param3=add($param1); echo '<br>$param1=='.$param1.'<br>'; //顯示爲$param1==1 //顯示爲$param2== 由於$param2是局部變量,函數運行完了之後就自動銷燬,其不能影響全局 echo '<br>$param2=='.$param2.'<!-- <br> -->'; //函數中的引用傳值 ↓↓ 注意,php不建議這樣使用,而且php.in裏面設置其會報錯; $param1 = 1; function add($param2){ $param2=3; return $param2; } //調用方法add,並將變量1的引用傳給變量2,此時兩個地址指向同一內存,改變其中一個,另一個也要被改變; $param3=add(&$param1); echo $param1; //3,內存已在函數內部改變; echo $param3; //3 ?>
Example3:code
<?php //給數組裏面的鍵值各增長10; $arr = array(3,5); foreach($arr as $k=>$v){ $v+=10;//1.更改無效,至關於遍歷出的鍵值扔給變量$v,而後更改變量$v的值,跟數組無關; echo $v." ";//輸出13 15; } foreach($arr as $k=>$v){ $arr[$k]+=10;//2.更改有效,直接更改鍵名裏面的值; echo $v;//輸出3,5; } foreach($arr as &$v){ $v+=10;//3.更改有效,遍歷的鍵值直接給了$v的地址,這個地址其實就是鍵名..$v+10就等於$arr[$k]+10; } ?>
而後咱們來看一下這道面試題:對象
$a = 1; $b = &$a; unset($a); echo $b; //??
可是要注意: unset並無真正銷燬變量的做用...僅僅是切斷了變量與內存之間的關係,內存只要還被引用着就不會被釋放; $b和$a同時指向1,切斷其中$a的關係,$b仍是指向1,因此上題不報錯,照樣輸出1。內存
另外補充一點: 在PHP中對象的傳值默認是引用傳值io
再看一題:
在作這題以前咱們回顧一下什麼是析構函數,而PHP中對象銷燬的方式有哪些:function
析構函數:對象銷燬時執行;注意在隱式銷燬中是在是全部php代碼執行完最後一行代碼的時候才銷燬,還有要注意在單入口文件下的MVC模式class
對象的銷燬:
Example1:
class Human { public $name = '張三'; public $gender = null; public function __destruct() { echo '死了!<br />'; } } $a = new Human(); $b = $c = $d = $a; unset($a); echo '<hr />'; //析構函數到底是觸發了幾回,是在線上觸發,仍是在線下觸發? 答案:
$b = $c = $d = $a;默認引用傳值,四個變量指向同一處內存,unset的時候對象仍是被仍是其它三個變量使用,因此對象並無被銷燬,因此析構函數是在線下觸發的(代碼執行完了,內存自動釋放)
Example2:
class Human { public $name = '張三'; public $gender = null; public function __destruct() { echo '死了!<br />'; } } $e = $f = $g = new Human(); unset($e); unset($f); unset($g); echo '<hr />'; //一樣的問題: 析構函數是在線上觸發仍是線下觸發?
我相信經過Example1的講解,應該很快知道答案是在線上觸發;在代碼運行完自動釋放內存以前因爲對象已經沒有被任何變量引用因此就自動釋放了內存....