Agent Grow Tech Notes
🐢

PHP浦島太郎がPHPのEnumを使ってみた

2024/09/03に公開

はじめに

こんにちは!
先日開発をしていて初めて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]
https://www.php.net/manual/ja/language.enumerations.php

記法は他の言語と少し違うものの、基本的な機能はほぼほぼ変わらないかなというのが第一印象。

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の定数といえば、こんな感じではないでしょうか。

Constant.php
const STATUS_NOT_WORK = 0;
const STATUS_DOING = 1;
const STATUS_COMPLETE = 2;
const STATUS_ERROR = 9;

すべてを1つの定数クラスにまとめていた時代、懐かしいです笑

それがenumを使うとこんなにもスッキリと!

Status.php
enum Status: int
{
    case NotWork = 0;
    case Doing = 1;
    case Complete = 2;
    case Error = 9;
}
使うときは.php
// 基本的には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の定義にメソッドを用意するだけです。

Status.php
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    => 'エラー',
        };
    }
}
使うときは.php
// バリデーションしたうえで使うよ
$name = Status::from($_POST['status'])->name();

エキサイティング!
呼び出しも定義もシンプルで最高ですね。[4]

今回はシンプルな文言取得のサンプルなので、そこまで旨味はなさそうに見えますかね。
例えば「機能によって文言が微妙に違う」なんて時に、nameと別のfunctionを用意するだけで対応できるので、Statusに関連する操作がひと目でわかって、とても!良い!のです。

読んでいる方も体感できる機会があると嬉しいです。

まとめ

Goodbye!定数クラス!
末永くよろしくEnum

脚注
  1. 他の言語を触っている身としては最近すぎる ↩︎

  2. https://www.php.net/manual/ja/class.backedenum.php ↩︎

  3. https://www.php.net/manual/ja/backedenum.tryfrom.php ↩︎

  4. そういえばmatchもPHP浦島太郎としては語りたい内容なのですが、話すのはまた別の機会に ↩︎

  5. https://www.php.net/manual/ja/backedenum.from.php ↩︎

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion