PHP浦島太郎がPHPのEnumを使ってみた
はじめに
こんにちは!
先日開発をしていて初めてPHPのenumに触れて「これは便利だぞ!!」となったので、新鮮な所感を交えつつ、その使い方を解説します。
対象読者
- PHPのenumのことを知りたい。
- 他の言語などでenumという概念は知っている。
- PHPのenumには触れたことがない。存在を知らなかった。
筆者について
- ブランク5年以上あってPHP開発に戻ってきた。
- PHPは、初めて使ったバージョンの5.x系のゆるゆるなイメージが強い。
- Java、C#の開発経験があるのでenumという概念は知っていた。
1. PHPのenumって何?
PHPのenumはバージョン8.1(2021年11月!!)から追加された機能です。 [1]
記法は他の言語と少し違うものの、基本的な機能はほぼほぼ変わらないかなというのが第一印象。
enum Fruit
{
case Apple;
case Lemon;
case Orange;
}
参考:https://www.php.net/manual/ja/language.enumerations.basics.php
ね、変わらないでしょ?
もちろん、各定義に特定の数字をもたせることもできます。
データベースを使う開発だと、こっちの使い方が大半というでしょうか。
enum Status: int
{
case NotWork = 0;
case Doing = 1;
case Complete = 2;
case Error = 9;
}
参考:https://www.php.net/manual/ja/language.enumerations.backed.php
実は、定義に数字などの別の値を紐づける場合は、PHPの内部的には別のインタフェース。[2]
他の言語だと1つにまとまっているので、最初はリファレンスを読むのに戸惑いましたが、使い方を覚えれば特に気になることもないですね!笑
2. PHPのenumの使い方
ここからは、私が具体的にどのようにPHPのenumを使っているかを紹介していきます。
前章の後半に紹介した「enum定義に数字を紐づける」パターンで使うことを想定しています。
2.1. 定数の代わりに使う
PHPの定数といえば、こんな感じではないでしょうか。
const STATUS_NOT_WORK = 0;
const STATUS_DOING = 1;
const STATUS_COMPLETE = 2;
const STATUS_ERROR = 9;
すべてを1つの定数クラスにまとめていた時代、懐かしいです笑
それがenumを使うとこんなにもスッキリと!
enum Status: int
{
case NotWork = 0;
case Doing = 1;
case Complete = 2;
case Error = 9;
}
// 基本的にはenumのまま使う
$status = Status::Doing;
// DBへの格納のように数値にしたいときだけ変換
$db_status = $status->value;
バリエーションがすぐに分かるので、可読性もバリバリ向上しますね!
2.2. バリデーションもできる
Webシステムのバリデーションであれば、システムが想定していない数値はエラーにしたいですね。
enumを使わないとこんな感じになるかと思います。
// マジックナンバー許すまじ
if (!in_array($_POST['status'], [0, 1, 2, 9])) {
// エラー処理
}
// 正攻法だとこうなるよねって感じだけど、不必要にコード量が多く見える
$status_list = [
STATUS_NOT_WORK,
STATUS_DOING,
STATUS_COMPLETE,
STATUS_ERROR,
];
if (!in_array($_POST['status'], $status_list)) {
// エラー処理
}
これがenumを使えばこう!
if (Status::tryFrom($_POST['status']) === null) {
// エラー処理
}
超!シンプル!
tryFrom
は定義されていない値が引数に渡された場合はnullを返すので、
結果がnullかどうかを見るだけでバリデーションできるわけです。[3]
2.3. コード値から日本語への変換もお手の物
数値から日本語の文言を表示したい。あるあるのケースですよね。
そんなときもenumは超便利。
さきほどのenumの定義にメソッドを用意するだけです。
enum Status: int
{
case NotWork = 0;
case Doing = 1;
case Complete = 2;
case Error = 9;
public function name(): string
{
return match ($this) {
Status::NotWork => '未着手',
Status::Doing => '対応中',
Status::Complete => '完了',
Status::Error => 'エラー',
};
}
}
// バリデーションしたうえで使うよ
$name = Status::from($_POST['status'])->name();
エキサイティング!
呼び出しも定義もシンプルで最高ですね。[4]
今回はシンプルな文言取得のサンプルなので、そこまで旨味はなさそうに見えますかね。
例えば「機能によって文言が微妙に違う」なんて時に、name
と別のfunctionを用意するだけで対応できるので、Statusに関連する操作がひと目でわかって、とても!良い!のです。
読んでいる方も体感できる機会があると嬉しいです。
まとめ
Goodbye!定数クラス!
末永くよろしくEnum!
Discussion