2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

今更ながら PHP の Enum 型を使ってみた

Posted at

まえがき

PHP8.1 が出たときは BenSampo/laravel-enum パッケージを利用していて、それで特に困っていなかったため Enum 型については詳しく調べていませんでした

多分僕と同じようにそのままズルズルと時間が過ぎてしまい、未だに Enum 型を使ったことない方は結構いらっしゃると思うので、そういう方のために使ってみたメモを残します

Enum

Enumerations (列挙型) とは、クラスのようなもので、特定かつ同一の型のスカラー値のみを持つことができる型を定義します

設定可能なスカラー値

  • int
  • string

利用可能なマジックメソッド

  • __call()
  • __callStatic()
  • __invoke()

サンプルコード

int 型の公開フラグ
(※Enum 型はインスタンスメソッド、静的メソッドどちらも定義可能です)

<?php
namespace App\Enums;

enum ViewFlg: int
{
    /**
     * チェック待ち
     *
     * @var int
     */
    case CHECK = 3;

    /**
     * 準備中
     *
     * @var int
     */
    case PREP = 2; 

    /**
     * 公開
     *
     * @var int
     */
    case SHOW = 1;

    /**
     * 非公開
     *
     * @var int
     */
    case HIDE = 0;

    /**
     * @return string
     */
    public function description(): string
    {
        return match ($this) {
            self::CHECK => 'チェック待ち',
            self::PREP  => '準備中',
            self::SHOW  => '公開',
            self::HIDE  => '非公開',
        };
    }

    /**
     * 公開中か判定
     *
     * @return bool
     */
    public function isShow(): bool
    {
        return (
            $this === self::SHOW
        );
    }

    /**
     * 存在チェック
     *
     * @static
     * @return bool
     */
    public static function has($value): bool
    {
        return (
            !is_null(self::tryFrom($value)
        );        
    }
}

なんと Trait も使えます!(サンプルコードでは使ってないですが)
定数も設定できます!(サンプルコードでは(ry

注意事項

異なる型のスカラー値を同一の Enum に設定することはできません。null も駄目です。
弊社では削除したレコードに view_flg = null を格納していたので、やっちまったなと思いました

駄目な例

// ? で表現するのはNG
enum ViewFlg: ?int
{
    case SHOW = 1;
    // int 型でないのでNG
    case DELETE = null;
}

何とか null を設定したい場合の抜け道を考える

Enum 型ではなく、プロパティに ViewFlg 型と null を許可すればいいかも知れません
ただ「削除」という description を持てないのでこれでも困るのですが…

class Commodity
{
    /**
     * @var ViewFlg|null $viewFlg
     */
    private readonly ?ViewFlg $viewFlg;

    /**
     * @param  ViewFlg|null $viewFlg
     */
    public function __construct(?ViewFlg $viewFlg)
    {
        $this->viewFlg = $viewFlg;
    }
}

まぁそういう場合は BenSampo/laravel-enum パッケージを使えばいいですね!!

Enum 型がデフォルトで持つ静的メソッド

from()

与えられたスカラー値を使用して、対応する列挙型のインスタンスを返却します
スカラー値が Enum 内に存在しない場合、例外が発生します

// ViewFlg::SHOW インスタンス
$viewFlg = ViewFlg::from(1);
// 例外が発生
$viewFlg = ViewFlg::from(5);

tryFrom()

与えられたスカラー値を使用して、対応する列挙型のインスタンスを返却します
存在しない場合、null を返却します

存在しない場合はデフォルト値を入れたいっていう用途とかでは使えそうです

// ViewFlg::SHOW インスタンス
$viewFlg = ViewFlg::from(1);
// null
$viewFlg = ViewFlg::from(5);

// デフォルト値として ViewFlg::SHOW を代入
$viewFlg = ViewFlg::from(5) ?? ViewFlg::SHOW;

case()

列挙型のすべてのケースを返却します

用途が難しいです…

// [
//    0 => ViewFlg::CHECK,
//    1 => ViewFlg::PREP,
//    2 => ViewFlg::SHOW,
//    3 => ViewFlg::HIDE,
// ]
$viewFlgs = ViewFlg::case();

インスタンス化後

当然インスタンスメソッドが使えます
name, value プロパティにもアクセスできます

$viewFlg = ViewFlg::from(1);

// 公開中
$viewFlg->description();
// true
$viewFlg->isShow();

// "SHOW"
$viewFlg->name;
// 1
$viewFlg->value;

あとがき

Laravel Model の casts プロパティにも設定出来るっぽいのでいいかも知れません

protected $casts = [
    'view_flg' => ViewFlg::class,
];

// なんで Enum 型なのに ::class が使えるんや?と対面で聞かれたのでここに書いておきますが
// ::class は「名前空間の完全修飾名」を取得するものなので
// 別に class とか Enum とか interface とか abstract とか関係ないのです

ただ今回使ってみて BenSampo/laravel-enum から乗り換えたくなる強い理由が見つかりませんでしたね…誰か教えてください

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?