あっぽログ
← 記事一覧に戻る

PHPのEnum完全入門:基本から応用まで使いこなす

PHPのEnumとは

PHP 8.1から正式に導入された Enum(列挙型) は、決まった値の集合を型安全に表現するための仕組みです。

以前は定数(const)や文字列で代替していた「ステータス」や「カテゴリ」などの概念を、より安全かつ表現力豊かに扱えるようになりました。

<?php

// 以前のやり方(定数で代替)
class OrderStatus
{
    const PENDING  = 'pending';
    const SHIPPED  = 'shipped';
    const DELIVERED = 'delivered';
}

// PHP 8.1 以降:Enumを使う
enum OrderStatus
{
    case Pending;
    case Shipped;
    case Delivered;
}

定数と違い、Enumはとして扱えるため、関数の引数や戻り値に使うと不正な値の混入を防げます。


Pure EnumとBacked Enum

PHPのEnumには2種類あります。

Pure Enum(純粋な列挙)

値を持たない最もシンプルな形です。

<?php

enum Direction
{
    case North;
    case South;
    case East;
    case West;
}

function move(Direction $dir): string
{
    return match ($dir) {
        Direction::North => '北へ移動',
        Direction::South => '南へ移動',
        Direction::East  => '東へ移動',
        Direction::West  => '西へ移動',
    };
}

echo move(Direction::North); // 北へ移動

型ヒントに Direction を指定することで、Direction::North 以外の値は渡せなくなります。

Backed Enum(値付き列挙)

文字列(string)または整数(int)を紐付けることができます。

<?php

enum Color: string
{
    case Red   = 'red';
    case Green = 'green';
    case Blue  = 'blue';
}

// 値からEnumを取得する
$color = Color::from('red');
echo $color->name;  // Red
echo $color->value; // red

// 存在しない値はfromだと例外、tryFromだとnullを返す
$unknown = Color::tryFrom('yellow'); // null

データベースやAPIとのやり取りでは Backed Enum が非常に便利です。保存時は .value を使い、取り出し時は from() / tryFrom() で安全に変換できます。


Enumにメソッドを定義する

Enumはクラスのようにメソッドやインターフェースを持てます。

<?php

enum Suit: string
{
    case Hearts   = 'H';
    case Diamonds = 'D';
    case Clubs    = 'C';
    case Spades   = 'S';

    public function label(): string
    {
        return match ($this) {
            Suit::Hearts   => 'ハート',
            Suit::Diamonds => 'ダイヤ',
            Suit::Clubs    => 'クラブ',
            Suit::Spades   => 'スペード',
        };
    }

    public function isRed(): bool
    {
        return match ($this) {
            Suit::Hearts, Suit::Diamonds => true,
            default                      => false,
        };
    }
}

$suit = Suit::Hearts;
echo $suit->label();           // ハート
var_dump($suit->isRed());      // bool(true)
echo $suit->value;             // H

ロジックをEnum自身にまとめることで、match式やif文が散らばるのを防げます。


インターフェースを実装する

EnumはPHPのインターフェースを implements できます。

<?php

interface HasLabel
{
    public function label(): string;
}

enum Status: int implements HasLabel
{
    case Active   = 1;
    case Inactive = 0;

    public function label(): string
    {
        return match ($this) {
            Status::Active   => '有効',
            Status::Inactive => '無効',
        };
    }
}

function printLabel(HasLabel $item): void
{
    echo $item->label() . PHP_EOL;
}

printLabel(Status::Active);   // 有効
printLabel(Status::Inactive); // 無効

インターフェースを活用することで、Enumを既存の設計に自然に組み込めます。


全ケースの一覧取得

cases() メソッドを使うと全ケースの配列を取得できます。

<?php

enum Permission: string
{
    case Read   = 'read';
    case Write  = 'write';
    case Delete = 'delete';
}

// 全ケースを列挙
foreach (Permission::cases() as $permission) {
    echo "{$permission->name}: {$permission->value}" . PHP_EOL;
}
// Read: read
// Write: write
// Delete: delete

// selectボックス用の配列に変換する例
$options = array_map(
    fn(Permission $p) => ['value' => $p->value, 'label' => $p->name],
    Permission::cases()
);

フォームのセレクトボックスやAPIレスポンスの生成など、実際の開発でよく使うパターンです。


Enumを使う上での注意点

  • Enumはインスタンス化できませんnew は使えない)
  • プロパティを持てません(定数 const は定義可能)
  • Pure Enumは from() / tryFrom() が使えません
  • Backed Enumの値は intstring のみ(float などは不可)
<?php

enum Season
{
    case Spring;
    case Summer;
    case Autumn;
    case Winter;

    // constは定義できる
    const WARM_SEASONS = [self::Spring, self::Summer];
}

var_dump(Season::WARM_SEASONS);
// array(2) { [0]=> enum(Season::Spring) [1]=> enum(Season::Summer) }

まとめ

種類値の有無from/tryFrom用途
Pure Enumなし使えない単純な区分け
Backed Enum (string)文字列使えるDB・API連携
Backed Enum (int)整数使えるフラグ・コード管理

PHPのEnumを使うと、コードの意図が明確になり、不正な値が混入するバグを型レベルで防げます。match式との相性も抜群なので、ステータス管理やカテゴリ分けが必要な場面でぜひ活用してみてください。

← 記事一覧に戻る