話說我這個使用參照到病態的人,來寫這個應該蠻適合的。

首先要提得是為甚麼要使用參照?
最重要的理由是為了減少複製變數的成本,這個成本包括記憶體的使用以及時間上的消耗。
如果你看過PHP的原始碼,PHP的變數基本上是由ZVAL這個結構所控制的,所以不管是不是使用參照,當我們作函數的參數傳遞、返回值以及變數賦值的時候,這個結構的產生是不可避免的。

這個問題還好,畢竟這個結構很小,但重點是一些複雜的變數型態,像是陣列、字串、物件等等,這些在複製花的成本上都比數字、邏輯值來的大,當然這也不能一概而論,但重點是在於,陣列、字串、物件這些型態的實際佔用的記憶體空間並不固定,更遑論像物件的複製可能還會有其他的問題產生。
當然啦,數字與邏輯值這些型態,用參照也得不到什麼額外的好處就是。

我個人是比較欣賞JavaScript的作法,傳值還是傳參照由型態決定,而決定的方式有公開的標準。

接下來我來談什麼樣的情況非得用參照不可?我發現有兩個原則:
  1. 無法確定你要操作的變數「在哪裡」的時候。
  2. 你要修改的是「原件」而非「副本」的時候。
第一種情況不太常見,不過程式寫多就會碰到,尤其是當你像我使用參照到病態的地步時,就會知道我說得是啥。
第二種情況則是比較常見,尤其函數的參數傳遞、返回值的應用。

另外要提的是,當一個變數被宣告為參照時,後續的賦值動作「全部」會被當成對被參照的變數作賦值動作,沒有辦法解除這種狀態,除非你unset這個參照變數。

除了上述的原則,有幾個情況建議使用參照:
  1. 函數的參數、返回值若為陣列、物件、資源時。
  2. 字串則要看函數調用時是否會直接給值而定,若不常發生直接給值的情況,也建議用參照。
對於函數傳回值的部份,有一點要注意。
當我們的自訂函數前面加上&符號時,代表會傳回參照,這個部份一直到調用函數然後傳回值這一段都是正確的。
但是!
當我們要把這個傳回值,直接變成另一個函數的參數,或是賦值給另外一個變數時,就不一定是參照了。

另外要說明的是,參照有其可用範圍,其範圍存在於函數之內,但不存在於此函數中呼叫另一函數之中,唯一的例外是此參照的對象是物件。

舉例說明:
function &a(){
...
}
function &b(&$a){
  $c = &$a; //$c = null
  $c = $a; // $c = $a的複製品 (若$a為物件的參照,則$c等同於$a所參照的原件)
  $a['a'] = 1; // 修改的是$a的原件(因為$a是用參照的方式傳進b()中)
...
}
$c = b(a());//這裡傳進去的a()的傳回值不是參照,$c取得的也不是b()傳回值的參照
$c = b(&a());//這個會引發錯誤:call_time_pass_reference
//正確作法
$temp = &$a();
$c = &b($temp);

$aa = array();
$bb = &$aa['a']['b']; // 這是OK的,尚未「運算」之前,參照可以指向任何東西
$bb = 1; // 這表示$aa['a']['b'] = 1
arrow
arrow
    全站熱搜

    HACGIS 發表在 痞客邦 留言(12) 人氣()