はじめに
先日、Ruby の強力なパターンマッチを試して楽しみました。その直後にたまたま久し振りに PHP に触る機会があったので PHP でもパターンマッチができないか調査してみました。
2020 年の PHP 8.0 にmatch 式が導入されていました。PHP でもパターンマッチができます!
試してみます。
PHP のmatch
式とは
公式ドキュメントに以下の通り記されています。
match 式は、値の一致をチェックした結果に基づいて評価結果を分岐します。
同僚が Elixir や Rust のパターンマッチを利用してスマートに課題解決しているのをみたことがあります。
PHP でも同様の記述ができるのでしょうか?これは期待できます。
PHP のmatch
式で素振り
せっかくなので自分で手を動かしてみようと思います。
Docker を利用すると氣軽に PHP の対話シェルが開けます。
docker run --rm -it php:8.3-cli-alpine
ためしに数字を漢字に変換して遊びます。
function number_to_kanji($n) {
return match ($n) {
1 => "壱",
2 => "弐",
3 => "参",
4 => "肆",
5 => "伍",
123 => "元氣",
default => "何じゃこれ?"
};
}
foreach (array(1, 2, 3, 4, 5, 123, 456) as $n) {
echo number_to_kanji($n).PHP_EOL;
}
壱
弐
参
肆
伍
元氣
なんじゃこれ?
うまくいきました!
ちなみに match
式は、全ての場合を網羅していないので、想定外のパターンをエラー(UnhandledMatchError
)にしたくなければdefault
を定義する必要があるようです。
配列のマッチもできるようです。
echo match ([1, 2, 3]) {
[1] => "壱",
[1, 2] => "壱弐",
[1, 2, 3] => "壱弐参",
default => "闘魂"
};
壱弐参
どうも PHP の match
式ではパターンマッチ実行時の代入はできなさそうです。
また、部分的なパターンマッチや_
で値を無視することもできなさそうです。
Ruby ではこんな記述ができました。
irb> config = {db: {user: "admin", password: "abc123"}}
irb> config => {db: {user: db_user}}
irb> db_user
=> "admin"
Elixir でもこんな記述ができました。
iex> config = %{db: %{user: "admin", password: "abc123"}}
iex> %{db: %{user: db_user}} = config
iex> db_user
=> "admin"
言語によりパターンマッチの仕様が異なるので注意が必要ですね。
PHP の match
式で Fizz Buzz
match
式では このように0
に対して条件式の結果をマッチするというユニークな記述ができるそうです。
function numberToFizzBuzz($n) {
return match (0) {
$n % 15 => "FizzBuzz" ,
$n % 3 => "Fizz",
$n % 5 => "Buzz",
default => $n,
};
}
function fizzBuzz($count) {
foreach(range(1, $count) as $n) {
echo numberToFizzBuzz($n).PHP_EOL;
}
}
fizzBuzz(16);
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
さいごに
文法になれてしまえば、PHP でも比較的簡単にパターンマッチができることがわかりました。
複雑なロジックを簡潔で明確なコードで表現できる可能性があると思いました。
今後、さらに実践的なプログラムでも試していこうと思います。