Contents

Strict Standards: Only variables should be passed by reference

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];

參考資料