2022年1月8日

三個點是什麼?介紹 PHP Splat Operator,直接拆開 array 並讓 function 傳入不固定數量的參數

PHP 有提供一個由三個點連在一起的語法 ... ,官方稱呼它為 ... operator 三點運算子. 或稱 Splat Operator。是 PHP 5.6 版後提供的新功能,它有兩種用法:

  1. 提供參數數量可以變化的函式,也就是可以傳入的參數數量不是固定的
  2. 陣列分拆 (unpack)
本篇是 PHP 系列,更多 PHP 相關文章請參考 → PHP 系列

1. 可變參數函式 Variadic functions

可變參數函式的意思是,傳入函式的參數數量是可以改變的,不是固定數量。

舉例來說,我們要將兩個數字相加,我們可以寫一個函式 sumTwo

function sumTwo($a, $b) 
{
    return $a + $b;
}

如果要將三個數字相加,原本的函式並不能使用,因為它只接受兩個參數。所以需要新增另一個函式 sunThree

function sumThree($a, $b, $c) 
{
    return $a + $b + $c;
}

但如果要將四個數字相加,又會需要新增一個函式,這樣的情況並不是一個好現象。

為了解決這個問題,PHP 提供了 ... operator 可以讓我們來改善這個狀況,用法如下,

function sum(...$numbers) {
    $result = 0;
    foreach ($numbers as $number) {
        $result += $number;
    }
    return $result;
}

echo sum(1); // 1
echo sum(1, 2); // 3
echo sum(1, 2, 3); // 6

所有傳入function sum(...$numbers) 的參數,都會被依序擺放到 ...$numbers 中,以陣列的方式儲存,因此在函式內就可以用陣列的方式操作它們。這邊的 sum 就是一種可變參數函式,因為它可以接受任一數量的參數。

另外,有 ... 的參數必須放在最後,因為 ... 只會蒐集最後剩下來的參數。例如下方範例,我們在 ...$numbers 之前,新增了一個 $multiplier ,那麼傳入的第一個參數會被先放入 $multiplier ,剩下的才會被放到 $numbers 中。

function multiplySum($multiplier, ...$numbers) {
    $result = 0;
    foreach ($numbers as $number) {
        $result += $number;
    }
    return $multiplier * $result;
}

echo multiplySum(10, 1, 2, 3); // 10 * 6 = 60

2. 陣列分拆 Array unpacking

這個用法可以把陣列拆分,變成一個一個元素。

如下方範例,我們嘗試把 $students 陣列印出來。直接印出來的話,會顯示它是一個 array 其中包含三個 string;但如果加入 ... 才印出,則會是獨立的三個 string。

$students = ['Tom', 'Jack', 'Sean'];

var_dump($students);
/*
array(3) {
  [0]=>
  string(3) "Tom"
  [1]=>
  string(4) "Jack"
  [2]=>
  string(4) "Sean"
}
*/

var_dump(...$students);
/*
string(3) "Tom"
string(4) "Jack"
string(4) "Sean"
*/

這個用途是什麼?它可以讓我們方便把陣列拆成獨立的引數 (Argument) 後,傳入函式中。

例如前面的例子用到的 sumTwo($a, $b),它只能接受兩個參數,因此如果我們想要把陣列丟入,就可以透過 ... 先行拆解:

function sumTwo($a, $b) 
{
    return $a + $b;
}

$numbers = [1, 2];
echo sumTwo(...$numbers); 

如果沒有 ... ,就只能這樣做:

$numbers = [1, 2];
echo sumTwo($numbers[0], $numbers[1]); 

結論

三點運算子是一個方便的功能,它的兩種用法是反過來的,根據擺放的位置不同,一個會把陣列拆開成多個變數,一個則把多個變數收納成陣列。雖然我認為這個用法一般上使用的機會不算高,但了解用法之後,應該可以設計出更具變化與彈性的程式吧!

參考

本篇是 PHP 系列,更多 PHP 相關文章請參考 → PHP 系列