可変長引数とは
引数の数が決まっていない、状況に応じて複数の引数を指定したいときに、関数の引数で指定する点(ドット)3つのことです。PHP5.6以降で使用することができます。
配列にまとめる
以下の関数を見てみましょう。
<?php
function listAnimals(...$a){
return $a;
}
$result = listAnimals('羊', '兎', '猫');
var_export($result);
?>
出力結果は以下の通りです。
# 出力結果
array (
0 => '羊',
1 => '兎',
2 => '猫',
)
7行目の関数発火時に指定した引数が配列として受け取れていることがわかりますね。このように、関数で引数を宣言する際に点(ドット)3つを手前につけることで、複数の値が飛んでくることを想定し、受取時に自動で配列に格納してくれるのです。
状況によって関数へ渡す値の数が異なる場合などに、わざわざ配列で受け渡しをする必要がないため便利です。
型の指定
では、可変長引数の型の指定方法を見てみましょう。
<?php
function sum(...$a){
return array_sum($a);
}
$result = sum(1, 2, 3, 4);
var_export($result);
?>
出力結果は以下の通りです。
# 出力結果
10
sum関数内のarray_sumを使って、配列の合計値を計算しています。わざわざ関数にする必要性はありませんが、そこについては今回スルーしましょう。
array_sumで合計値を出す以上、配列内に含まれるものはすべて数字でなくてはなりません。数値が文字列として指定されていた場合は数値に変換して計算されますが、数値でなければ0として認識されてしまうのです。
以下のコードを見てみましょう。
<?php
function sum(...$a){
return array_sum($a);
}
$result = sum(1, 2, 3, 4, '5');
var_export($result);
?>
出力結果は以下の通りです。
# 出力結果
10
追加した5が計算されていないことがわかります。これは5が全角数字だからです。しかし計算結果が出力されていると、見逃してしまう可能性も考えられます。
そうならないためにも、可変長引数で受け取る値の型を指定します。
<?php
function sum(int ...$a){
return array_sum($a);
}
$result = sum(1, 2, 3, 4, '5');
var_export($result);
?>
結果は以下の通りです。
# 出力結果(エラー)
PHP Fatal error: Uncaught TypeError: Argument 5 passed to sum() must be of the type int, string given, called in...
エラーが表示されましたね。これなら開発段階で予期しない結果を生む危険性を回避することができます。
可変長引数を型指定する場合は、ドット3つの前に型を宣言します。そうすれば受け取るすべての値を指定した型で検証することができます。
サンプルコード「多次元連想配列の検索」
では可変長引数を使った実用的な関数のサンプルコードを見てみましょう。
今回実装したのは、多次元連想配列のキーと値を指定して、該当する行を取り出すという処理になります。複数キーを使ったandやorの検索はできませんが、多次元連想配列を簡易データベースのように扱えるような関数を実装します。
<?php
# 完成コード「多次元連想配列の検索」
function searchAnimals($key, ...$vals){
$animals = [
0 => ['id' => 1, 'name' => 'うさぎ', 'type' => '草食'],
1 => ['id' => 2, 'name' => 'ライオン', 'type' => '肉食'],
2 => ['id' => 3, 'name' => 'シマウマ', 'type' => '草食'],
3 => ['id' => 4, 'name' => 'アヒル', 'type' => '雑食'],
];
$column = array_column($animals, $key);
$results = [];
foreach($vals as $val){
$indexs = array_keys($column, $val);
foreach($indexs as $index){
$results[] = $animals[$index];
}
}
return $results;
}
$result = searchAnimals('name', 'うさぎ');
var_export($result);
?>
出力結果は以下の通りです。
# 出力結果
array (
0 =>
array (
'id' => 1,
'name' => 'うさぎ',
'type' => '草食',
),
)
25行目のsearchAnimalsで第一引数に検索するキー、第二引数で検索する値を指定しています。nameキーがうさぎに一致するものを検索して、該当結果が取得できました。
第二引数は可変長引数になっているので、複数検索が可能です。25行目を以下のように変更してみましょう。
$result = searchAnimals('type', '草食', '肉食');
出力結果は以下の通りです。
# 出力結果
array (
0 =>
array (
'id' => 1,
'name' => 'うさぎ',
'type' => '草食',
),
1 =>
array (
'id' => 3,
'name' => 'シマウマ',
'type' => '草食',
),
2 =>
array (
'id' => 2,
'name' => 'ライオン',
'type' => '肉食',
),
)
typeが草食と肉食に該当する「うさぎ」「シマウマ」「ライオン」が問題なく取得できましたね。
では、どういった処理になっているかを順に見てみましょう。まずは関数の引数についてです。
searchAnimals($key, ...$vals)
第一引数にキー名、第二引数に可変長引数指定で値を指定します。複数キーを使ったand検索などはできませんが、複数の値に該当するものを検索することが可変長引数のおかげで可能にしています。
次に動物データの多次元連想配列を準備します。
$animals = [
0 => ['id' => 1, 'name' => 'うさぎ', 'type' => '草食'],
1 => ['id' => 2, 'name' => 'ライオン', 'type' => '肉食'],
2 => ['id' => 3, 'name' => 'シマウマ', 'type' => '草食'],
3 => ['id' => 4, 'name' => 'アヒル', 'type' => '雑食'],
];
後の説明でわかりやすいように、一層目に0から順にインデックスを指定しています。
※番号が間違うと意図しない検索結果が変える可能性があるため、実装する際は省略をオススメします
最初の処理は、指定されたキーを使って多次元配列からカラム(列)を取り出します。
$column = array_column($animals, $key);
$keyでtypeが指定されていた場合、$columnは以下の値が格納されます。
# 出力結果
array (
0 => '草食',
1 => '肉食',
2 => '草食',
3 => '雑食',
)
typeの列だけを取り出しています。上から順番に取得しているため、$animalsのインデックスと$columnsのインデックスは一致しています。
では次の処理を見てみましょう。
$results = [];
foreach($vals as $val){
$indexs = array_keys($column, $val);
foreach($indexs as $index){
$results[] = $animals[$index];
}
}
$resultsに結果を格納するためのから配列を準備します。
最初のforeach($vals as $val)で、検索する値を順番に処理します。searchAnimalsの第二引数で「草食」と「肉食」が指定されていた場合は、順に先程取得した$columnに該当する値があるかを検索するためです。
$indexsに格納しているarray_keys($column, $val)を確認してみましょう。「草食」が$valに入っている1回目であれば、以下のような結果になります。
# 出力結果
array (
0 => 0,
1 => 2,
)
array_keysの返り値は配列になります。今回のインデックス番号は必要ないので、以下のように省略した値で見ていきましょう。
# 出力結果(インデックス省略)
array ( 0, 2 )
0番と2番が返ってきました。これは、$animalsのインデックス番号と一致しています。このインデックス番号に該当する行を$animalsから取り出すために、更にforeachを使って処理をしています。
foreach($indexs as $index){
$results[] = $animals[$index];
}
これで、インデックス番号を順番に$animalsに当てはめ、その結果を$resultsに順番に格納していきます。
草食が終われば、次は肉食を検索して、同じように該当したものを$resultsに格納していきます。
あとは、returnで検索結果を格納した$results返却するだけです。
return $results;
# 出力結果
array (
0 =>
array (
'id' => 1,
'name' => 'うさぎ',
'type' => '草食',
),
1 =>
array (
'id' => 3,
'name' => 'シマウマ',
'type' => '草食',
),
2 =>
array (
'id' => 2,
'name' => 'ライオン',
'type' => '肉食',
),
)
まとめ
いかがだったでしょうか。
今回は「PHPの可変長引数について」を実用的な多次元連想配列の検索サンプルを使ってご紹介しました。
可変長引数を使えば、関数の処理を簡略化したり、複数の値を引数として指定する可能性がある関数の汎用性を高くすることができます。
現在PHPを使って開発をしている人や、これからPHPを学習しようと考えている人は、ぜひ参考にしてくださいね。