移除在使用傳參考呼叫函式時包含參考符號(&,即函式定義使用 &)的功能,會降低程式碼的可讀性,因為必須查看函式定義才能知道傳遞的變數是否為傳參考(即可能被修改)。如果函式呼叫和函式定義都要求參考符號(即 &),則可讀性會提高,並且還可以減少程式碼本身出現疏忽錯誤的可能性。5.4.0 版強制使用致命錯誤,現在迫使每個人都必須撰寫可讀性較差的程式碼。也就是說,一個函式只是使用變數,還是可能會修改它...現在我們必須找到函式定義並實際查看它才能知道,而在以前我們可以立即知道意圖。
您可以透過引用將變數傳遞給函式,以便函式可以修改該變數。語法如下:
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
// $a 現在是 6
?>
注意事項:函式呼叫時不需要使用參考符號 (&),只有在函式定義時才需要。僅在函式定義中使用參考符號就足以正確地以傳址方式傳遞參數。
以下情況可以傳址:
foo($a)
從函式返回的參考,例如:
<?php
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
不應以傳址方式傳遞其他表達式,因為結果未定義。例如,以下以傳址方式傳遞的範例是無效的:
<?php
function foo(&$var)
{
$var++;
}
function bar() // 注意缺少 &
{
$a = 5;
return $a;
}
foo(bar()); // 會產生通知
foo($a = 5); // 表達式,而非變數
foo(5); // 會產生致命錯誤
class Foobar {}
foo(new Foobar()) // 從 PHP 7.0.7 開始會產生通知
// 通知:只應傳遞變數的參考
?>
移除在使用傳參考呼叫函式時包含參考符號(&,即函式定義使用 &)的功能,會降低程式碼的可讀性,因為必須查看函式定義才能知道傳遞的變數是否為傳參考(即可能被修改)。如果函式呼叫和函式定義都要求參考符號(即 &),則可讀性會提高,並且還可以減少程式碼本身出現疏忽錯誤的可能性。5.4.0 版強制使用致命錯誤,現在迫使每個人都必須撰寫可讀性較差的程式碼。也就是說,一個函式只是使用變數,還是可能會修改它...現在我們必須找到函式定義並實際查看它才能知道,而在以前我們可以立即知道意圖。
<?php
// PHP >= 5.6
// 這裡我們使用 'use' 運算子在函式作用域內建立一個變數。雖然看起來新建立的變數與函式外部的 '$x' 有關,但實際上我們是在函式內建立一個與函式外部的 '$x' 變數無關的 '$x' 變數。我們指的是相同的名稱,但在記憶體中的位置不同。
$x = 10;
(function() use ($x){
$x = $x*$x;
var_dump($x); // 100
})();
var_dump($x); // 10
// 現在,使用參考 (&) 就會產生神奇的效果。現在我們實際上是在存取函式作用域外部的 '$y' 變數的內容。我們在函式內對變數 '$y' 執行的所有操作都會反映在此函式作用域外部。記住,這在函數式編程範式中將是一個不純函式,因為我們正在透過參考更改變數的值。
$y = 10;
(function() use (&$y){
$y = $y*$y;
var_dump($y); // 100
})();
var_dump($y); // 100
?>
注意 unset() 會銷毀參考
$x = 'x';
change( $x );
echo $x; // 輸出 "x" 而不是 "q23" ---- 移除 unset() 後輸出為 "q23" 而不是 "x"
function change( & $x )
{
unset( $x );
$x = 'q23';
return true;
}
透過參考傳遞的參數可以有預設值。
您可以使用 func_num_args() 來判斷變數是否確實已傳遞。
<?php
function refault( & $ref = 'Do I have to be calculated?'){
echo '參數數量:'. func_num_args()."\n";
echo "原始值:{$ref}\n";
if( func_num_args() > 0 ) $ref = '是的,計算結果很耗時:' . sleep(1);
else $ref = '不用。';
echo "新值:{$ref}\n";
}
$result = 'Do I have to be calculated?';
refault( $result );
echo "結果:{$result}\n";
// 參數數量:1
// 原始值:Do I have to be calculated?
// 新值:是的,計算結果很耗時:0
// 結果:是的,計算結果很耗時:0
refault();
// 參數數量:0
// 原始值:Do I have to be calculated?
// 新值:不用。
?>
在類別中,以傳址方式傳遞不存在的陣列元素時,這些元素會以 null 值新增到陣列中。與一般函式相比,這種行為會將函式從拋出錯誤改為在傳址陣列中使用新鍵值建立新的 (null) 項目。
<?php
class foo {
public $arr = ['a' => 'apple', 'b' => 'banana'];
public function normalFunction($key) {
return $this->arr[$key];
}
public function &referenceReturningFunction($key) {
return $this->arr[$key];
}
}
$bar = new foo();
$var = $bar->normalFunction('beer'); // 注意:錯誤。未定義索引 beer
$var = &$bar->referenceReturningFunction('beer'); // 沒有錯誤。$bar 的值現在為 null
var_dump($bar->arr);
/**
[
"a" => "apple",
"b" => "banana",
"beer" => null,
],
*/
?>
這絕非「錯誤」—— 框架的運作符合設計,但需要仔細思考才能理解發生了什麼事。PHP7.3