PHP 的 Strict Standards: Only variables should be passed by reference 錯誤(在 PHP 7+ 變為 Notice 或 Warning)是初學者常遇到的問題。這個錯誤的根本原因是試圖將「非變數」傳給「需要引用的參數」。
問題原因
PHP 的部分內建函式的參數是「以引用方式傳遞」(pass by reference),例如 array_shift()、array_pop()、end()、reset() 等。
PHP 的引用(reference)必須指向一個真實的變數記憶體位置。而函式的回傳值是一個「臨時值」,沒有固定的記憶體位置,因此無法取引用。
常見觸發錯誤的寫法:
1
2
3
4
5
6
7
8
|
// ❌ 錯誤:嘗試對函式回傳值取引用
$price = array_shift(get_product_price($product_key));
// ❌ 錯誤:end() 需要引用參數
$last = end(get_items());
// ❌ 錯誤:array_pop() 需要引用參數
$value = array_pop(explode(',', $string));
|
解決方法:先賦值給變數
將函式回傳值先儲存到一個具名變數,再傳入需要引用的函式:
1
2
3
4
5
6
7
8
9
10
11
|
// ✅ 正確
$product_price = get_product_price($product_key);
$price = array_shift($product_price);
// ✅ 正確
$items = get_items();
$last = end($items);
// ✅ 正確
$parts = explode(',', $string);
$value = array_pop($parts);
|
常見觸發情境與修正
array_shift() — 取出陣列第一個元素
1
2
3
4
5
6
|
// ❌
$first = array_shift(getData());
// ✅
$data = getData();
$first = array_shift($data);
|
array_pop() — 取出陣列最後一個元素
1
2
3
4
5
6
7
|
// ❌
$last = array_pop(explode('.', 'file.tar.gz'));
// ✅
$parts = explode('.', 'file.tar.gz');
$last = array_pop($parts);
// $last = 'gz'
|
end() / reset() — 移動陣列指標
1
2
3
4
5
6
|
// ❌
$last = end(array_values($array));
// ✅
$values = array_values($array);
$last = end($values);
|
sort() / usort() — 排序函式
1
2
3
4
5
6
|
// ❌(sort 需要引用參數)
sort(getArray());
// ✅
$arr = getArray();
sort($arr);
|
為什麼只有變數可以傳引用?
PHP 引用的本質是「兩個名稱指向同一個記憶體位置」。引用傳遞的目的是讓函式能修改外部的值:
1
2
3
4
5
6
7
|
function addOne(&$value) {
$value++;
}
$num = 5;
addOne($num);
echo $num; // 6
|
如果允許對臨時值(函式回傳值)取引用,修改後的值沒有地方儲存,也無法反映到呼叫端,在語意上毫無意義,因此 PHP 禁止這樣做。
更簡潔的替代寫法
對於 end() 取最後一個元素,可以用 array_slice() 避免引用問題:
1
2
3
4
|
// 取最後一個元素,不需要修改原陣列
$last = array_slice(getArray(), -1)[0];
// 或
$last = array_slice(getArray(), -1, 1)[0];
|
參考資料