こんにちは、Nakaです。

PHP 8.1 で Enum が導入されて以降、ステータス管理や種別管理を Enum で表現するコードはかなり一般的になりました。

一方で、実際のアプリケーションでは「この Enum をどう表示するか」という問題が必ず出てきます。管理画面・API・UI コンポーネントなど、**人間向けの意味(ラベル)**をどこで、どう管理するかは意外と悩ましいポイントです。

本記事では、Enum case に表示用ラベルを持たせる設計としてアトリビュートを用いた方法を紹介し、さらに PHPStan によってそのルールを機械的に保証する方法までを解説します。

Enum と表示用ラベルの設計

以下はよくあるステータス管理です。

enum Status: int
{
    case Draft = 0;
    case Published = 1;
}

この Enum 自体はとても分かりやすく、ロジック上はこれで十分です。ただ、実際のアプリケーションではこういう要件が出てきます。

つまり、

Enum の case に「表示用の名前(ラベル)」を持たせたい

という要求です。この問題に対して、よく見かける実装はいくつかあります。


よくある実装例とその問題点

配列でマッピング:

const LABELS = [
    Status::Draft->value => '下書き',
    Status::Published->value => '公開中',
];

public function label(): string
{
    return self::LABELS[$this->value];
}

switch で分岐:

public function label(): string
{
    return match ($this) {
        Status::Draft => '下書き',
        Status::Published => '公開中',
    };
}