こんにちは、さるまりんです🐵
今回は、PHP 8から導入された新しい分岐構文「match
式」についてです。
switch
構文に似ているようで、実はまったく違う書き方とメリットがあるみたい。
Dockerを使ってでPHP 7と8の環境を切り替えながら、実際に動かして比較してみました!
これまでのswitch
文とその課題
PHPで条件分岐といえば、思い浮かぶのがswitch
。
例えば以下のように使います。
<?php
$fruit = 'apple';
switch ($fruit) {
case 'apple':
echo "It's an apple\n";
break;
case 'banana':
echo "It's a banana\n";
break;
default:
echo "Unknown fruit\n";
}
でも、ちょっと使いづらいかも…
break
を書き忘れるとおかしなことになりますし、値を返したい時に冗長になってしまいます。
また、switch
の構文は式としては使えなくて、値をそのまま代入することができません。
match
式でコードがスッキリ!
PHP 8では、switch
に代わるスマートな書き方としてmatch
が登場しました。
<?php
$fruit = 'banana';
echo match ($fruit) {
'apple' => "It's an apple\n",
'banana' => "It's a banana\n",
default => "Unknown fruit\n",
};
match
のメリットは?
=>
で結果を返す式ベースになっています。
そして、switch
と違い、break
が不要です。
条件に一致するか否かの比較は===
で厳密に比較されます。
また、全ケースを網羅しないと例外となり、バグを見逃しにくくなっています。
値を返す使い方(match
の真価)
以下、値を返す例です。HTTPレスポンスのステータスに応じて、文言を返すようになっています。
<?php
$status = 302;
$message = match ($status) {
200 => 'OK',
301, 302 => 'Redirect',
404 => 'Not Found',
500 => 'Internal Server Error',
default => 'Unknown status',
};
echo $message . PHP_EOL;
複数の値に対して同じ結果を返す書き方がシンプルになっていますね。
で、上の例ではmatch
からそのまま変数$message
に代入しています。
注意:ケースが不足するとエラーになる
default
は必須ではないけど、全てのケースをカバーできてないと例外を投げます。
<?php
$fruit = 'grape';
echo match ($fruit) {
'apple' => 'Apple',
'banana' => 'Banana',
// default を忘れている!
};
実行結果:
Fatal error: Uncaught UnhandledMatchError
なので、全パターンを網羅するように設計する必要があるし、「その他」「デフォルト」はdeault
として入れるようにするのがいいかと思いました。
もう少し複雑な使い方
例:得点による評価を返す
match(true)
を使うと、こんなこともできます。
<?php
$score = 82;
$rank = match (true) {
$score >= 90 => 'A',
$score >= 70 => 'B',
$score >= 50 => 'C',
default => 'D',
};
echo "Score: $score, Rank: $rank\n";
どうですか?
こんなふうに条件評価の分岐に使うこともできます。
例:フォームの値によってアクションを分ける
<?php
$action = $_POST['action'] ?? 'none';
$result = match ($action) {
'save' => '保存しました',
'delete' => '削除しました',
'update' => '更新しました',
default => '不明なアクション',
};
echo $result;
HTMLフォームから送られてきた値によって動作を分けています。
Dockerを使ってPHP 7/8 の切り替え
ローカルに複数バージョンのPHPをインストールすると何か変なことが起きたりしそうなので、Dockerで独立した環境を作って試してみました。
# docker-compose.yml
services:
php7:
image: php:7.4-cli
volumes:
- ./src:/app
working_dir: /app
command: php switch_test.php
php8:
image: php:8.3-cli
volumes:
- ./src:/app
working_dir: /app
command: php match_test.php
# 実行
docker-compose run --rm php7
docker-compose run --rm php8
これでphp7
でswitch_test.php
、php8
でmatch_test.php
を実行して試すことができます。
値に応じた数値からラベルへの変換処理、フォームの分岐処理、REST APIのステータス表示やテストデータの出力、いろんな使い道がありそうです。
switch
で長くちょっと読みにくいコードを書いていたところにこのmatch
を使えないか考えながら新しいものに使いこなせるようになっていきたいと思います。
読んでくださってありがとうございました。
それではまた!