PHP8では名前付きパラメータ(引数)が使えるようになりました。関数呼び出しのパラメータの順番が無視できるようになります。
とくに、デフォルト値が指定されたパラメータを使うときに便利。
PHP8はデータの厳格化がポイントになってるんですがその一環です。
2020年11月26日、5年ぶりにphpのメジャーバージョンが上がりました。php8です。
メジャーアップデートだけに変更点も大きいです。
関数を呼び出すときに、パラメータ名を指定できるようになったのもそのひとつ。
まずは使い方を見てみましょう。そのあとに、どれだけ便利になったのかを見ていきます。
名前付きパラメータ
名前付きパラメータは、ソースコードを見たほうが早いです。
<?php
function sum1($data1 = 2, $data2 = 3 ) {
echo $data1 . ' + ' . $data2 . ' = ';
return $data1 + $data2;
}
$inp1 = 3;
$inp2 = 5;
echo sum1( data1: $inp1, data2: $inp2 ) . PHP_EOL;
php80 sample.php
3 + 5 = 8
[ パラメータ変数名 ] :(コロン) [入力値]
functionのパラメータ変数名を使うので、修正するのは呼び出し元だけ。修正内容もかんたんです。
もちろんですが、PHP7ではエラーになります。
php sample.php
PHP Parse error: syntax error, unexpected ':', expecting ')' in /home/sample/sample.php on line 11
『コロンなんて知らねーよ!』というエラーです。
名前付きパラメータと従来のパラメータの共存
これまでの名前無しパラメータと、名前付きパラメータは共存できます。しかし、注意点が。
混在パラメータにはルールがあり、それに従わないとエラーになります。
名前付きパラメータの後ろに名前無しは使えない
名前付きパラメータの後ろには名前無しパラメータは使えません。
<?php
function sample( $param1 = 'aaa' , $param2 = 'bbb' , $param3 = null ) {
echo 'param1: ' . var_export( $param1, true ) . PHP_EOL;
echo 'param2: ' . var_export( $param2, true ) . PHP_EOL;
echo 'param3: ' . var_export( $param3, true ) . PHP_EOL;
}
sample( param1: '111', '222', '333' );
php80 sample2.php
PHP Fatal error: Cannot use positional argument after named argument in /home/sample/sample2.php on line 9
従来のパラメータは、名前付きパラメータに対して『位置パラメータ』と呼ぶらしい。
パラメータの順番が一致しないといけないからでしょう。
名前付きパラメータの後ろに使えない理由は、その位置がずれることがあるから。
もちろんですけど、位置パラメータが前にある分にはOKです。
sample( '111', param3: 'sample', param2: '222' );
php80 sample2.php
param1: '111'
param2: '222'
param3: 'sample'
名前付きパラメータの順番は関係ありません。
もうひとつは、位置パラメータは順番が一致しないといけません。
sample( '111', '222', param3: 'sample' );
php80 sample2.php
param1: '111'
param2: '222'
param3: 'sample'
名前付きパラメータでの上書き禁止
位置パラメータを使っているのに、それを名前付きパラメータでも使っているとNGです。
sample( '111', '222', param2: 'sample' );
PHP Fatal error: Uncaught Error: Named parameter $param2 overwrites previous argument in /home/sample/sample2.php:9
Stack trace:
#0 {main}
thrown in /home/sample/sample2.php on line 9
『オーバーライド(上書き)してんじゃねーよ!』って出ます。
デフォルト値の意味を考えよう
名前付きパラメータが出てきたことで、パラメータのデフォルト値の意味が変わっています。
ひとつは今までと同じ、『指定されなかったときのデフォルト値』。
そして新しく出てきたのは、『必須パラメータか否か』
デフォルト値 | 必須パラメータ |
---|---|
あり | ✕ |
なし | ○ |
<?php
function sample( $param1=null , $param2 , $param3, $param4 ) {
echo 'param1: ' . var_export( $param1, true ) . PHP_EOL;
echo 'param2: ' . var_export( $param2, true ) . PHP_EOL;
echo 'param3: ' . var_export( $param3, true ) . PHP_EOL;
echo 'param4: ' . var_export( $param4, true ) . PHP_EOL;
}
sample( '111', param4: '444', param3: '333' );
php80 sample2.php
PHP Fatal error: Uncaught ArgumentCountError: sample(): Argument #2 ($param2) not passed in /home/sample/sample2.php:3
Stack trace:
#0 /home/sample/sample2.php(10): sample()
#1 {main}
thrown in /home/sample/sample2.php on line 3
sample( '111', '222', param4: '444', param3: '333' );
// または
// sample( '111', param4: '444', param3: '333', param2: '222' );
php80 sample2.php
param1: '111'
param2: '222'
param3: '333'
param4: '444'
2種類のパラメータの共存はやめよう!
位置パラメータ(従来のパラメータ)と名前付きパラメータの共存は、はっきりいってやめたほうがいい。混乱の元だから。
例えばこのコードを実行します。
<?php
function sample( $param1=null , $param2 , $param3, $param4 ) {
echo 'param1: ' . var_export( $param1, true ) . PHP_EOL;
echo 'param2: ' . var_export( $param2, true ) . PHP_EOL;
echo 'param3: ' . var_export( $param3, true ) . PHP_EOL;
echo 'param4: ' . var_export( $param4, true ) . PHP_EOL;
}
sample( '111', '222', param3: '333' );
もちろん、param4が必須パラメータなので、エラーになります。
php80 sample2.php
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function sample(), 3 passed in /home/sample/sample2.php on line 10 and exactly 4 expected in /home/sample/sample2.php:3
Stack trace:
#0 /home/sample/sample2.php(10): sample()
#1 {main}
thrown in /home/sample/sample2.php on line 3
そうすると、こういう修正をしがちです。
sample( '111', '222', param3: '333', '444' );
が、これもエラー。今度は、名前付きパラメータの後ろに位置パラメータがあるから。
php80 sample2.php
PHP Fatal error: Cannot use positional argument after named argument in /home/sample/sample2.php on line 10
エラー発生。
修正してまたエラー発生。
(最悪、これが続く。)
こういうことが起きると普段ならできるのに、負のループに陥りやすいので時間がもったいない。
混乱の原因になるものを潰していくのもプログラミングのコツです。こういうコーディングはやめましょう。
名前付きパラメータは、使うなら全パラメータに使う。
使わないなら全パラメータに使わない。
共存はやめる。
というか、関数の呼び出し元でパラメータの意味が分かるし、コーディング的には絶対に使ったほうがいい。読みやすいから。
関数の呼び出し元でパラメータの意味が分かると、バグのリサーチで関数内まで読まなくていいこともあって助かる。
バグの予防にもなる。
パラメータの指定がスッキリ!
長々といろいろなことを言ってきましたが、名前付きパラメータの一番のメリットは、関数呼び出しのパラメータ数が最小限で済むことです。
<?php
function sample( $param1 = null , $param2 = true , $param3 ) {
echo 'param1: ' . var_export( $param1, true ) . PHP_EOL;
echo 'param2: ' . var_export( $param2, true ) . PHP_EOL;
echo 'param3: ' . var_export( $param3, true ) . PHP_EOL;
}
param1, param2はデフォルト値のままにしてsample()を使いたいとき、今まではこんな感じで使っていました。
$param3 = "sample";
sample( null, true, $param3);
せっかく関数のデフォルト値が設定されているのに、関数を使うときにはそのデフォルト値が何なのかを調べて指定する必要がありました。
(順序も守らないといけないし。)
名前付きパラメータでは、デフォルト値を知る必要はありません。
$param3 = "sample";
sample( param3: $param3);
スッキリしていいですね? また、デフォルト値が変わっても関数を呼び出す側で修正する必要がありません。
個人的には、名前付きパラメータを使うのをコーディング規約に入れてもいいんじゃないかと思います。
PHP8以降でしか使わないという前提があれば。
PHP7でも動くようにする場合は使えない。もしくはPHPバージョンごとに処理を分ける対応が必要。
あえて作業が増えるようなら、PHP7のサポートが終わるまで名前付きパラメータを使わない選択肢もある。