PHPに詳しいアンミカ「Enumって2種類あんねん」
この記事は Laravel Advent Calendar 2023 21日目の記事です。
疑問
caseに対応する値を定義する方法は2種類があるが、どちらで記述するのが良いのか?
① BackedEnum
enum SIGNAL:string{
case RED='赤';
case YELLOW='黄';
case BLUE='青';
}
② PureEnum
enum SIGNAL{
case RED;
case YELLOW;
case BLUE;
public function label():string{
return match($this){
self::RED=>'赤',
self::YELLOW=>'黄',
self::BLUE=>'青',
};
}
}
PureEnumとBackedEnum
上記の①のように、caseの右辺に対応する値(※以後、スカラー値と呼ぶ)を定義しているEnumをBackedEnumと言う。一方、②のようにスカラー値を定義していないEnumをPure Enumという。
PureEnumとBackedEnumの大きな違いは、BackedEnumインターフェースを実装しているか否かであり、BackedEnumはそれを実装しています。なのでBackedEnumインターフェースについて考えることで、どのような意図でスカラー値を定義すべきかを理解出来ると思います。
interface BackedEnum{
public static from(int|string $value): static
public static tryFrom(int|string $value): ?static
}
BackedEnumの使い所
fromとtryFromはスカラー値からEnumを生成するためのメソッドです。スカラー値に対応するcaseが存在しない場合に、fromではErrorが生じますが、tryFromではnullを返します。
SIGNAL::tryFrom('赤') //SIGNAL::RED
SIGNAL::from('赤') //SIGNAL::RED
SIGNAL::tryFrom('黒') //null
SIGNAL::from('黒') //Error
上記メソッドから、BackedEnumはデータベースに保存しているマスタやユーザー入力値から対応するEnumを生成するために用意されていると思いました。
なので、Enumの値をユーザーへの表示のために変換したい場合はmatchを用いたメソッドを定義する。DBやユーザー入力値からのEnumへの変換のように、アプリケーション外部からのマッピングが必要な際は、スカラー値の定義を用いるのが良いと思いました。
ユーザー表示への変換とアプリケーション外部からのマッピングの併用
redやyellowという文字列をマスタとしてDBで管理している場合はスカラー値として定義し、ユーザー表示のための変換はメソッドで定義します。
こうすることで、ユーザー表示向けの変換を複数定義することが可能になります。
enum SIGNAL:string{
case RED="red";
case YELLOW="yellow";
case BLUE="blue";
public function label():string{
return match($this){
self::RED=>'赤',
self::YELLOW=>'黄',
self::BLUE=>'青',
};
}
public function label2():string{
return match($this){
self::RED=>'止まれ!',
self::YELLOW=>'気をつけて渡れ!',
self::BLUE=>'渡れ!',
};
}
}
Enumの基本的な使い方まとめ
1. name,valueプロパティ
nameでcaseに定義した値にアクセスできるので、単に各enumに対応する文字列にアクセスしたいだけなら、スカラー値を定義する必要はない。
enum SIGNAL: string
{
case RED = "red";
case YELLOW = "yellow";
case BLUE = "blue";
}
$name=SIGNAL::RED->name; // RED
$value=SIGNAL::RED->value; // red
2. そのまま比較可能
enumはシングルトンなので、objectのまま比較可能です。nameやvalueプロパティを取り出して比較する必要はない。
$red1 = SIGNAL::RED;
$red2 = SIGNAL::RED;
echo $red1 === $red2; // true
3. Eloquentのcastsプロパティに指定可能
protected $casts = [
'color' => SIGNAL::class
];
まとめ
BackedEnumは、DBやユーザー入力などのアプリケーション外部の値からenumへ変換するために存在していると思います。よって、単にアプリケーション内部だけで用いるenumにはPureEnumを選択するのが良いと思いました。
こうすることで、そのenumが外部の値に依存して(Backed)いるのか否かが明確になります。依存している場合としていない場合では、enumの値を書き換える際に考慮すべき範囲が異なってくるので、メンテナンスしやすくなると思いました。
オンライン家庭教師マナリンクを運営するスタートアップNoSchoolのテックブログです。 manalink.jp/ 創業以来年次200%前後で売上成長しつつ、技術面・組織面での課題に日々向き合っています。 カジュアル面談はこちら! forms.gle/fGAk3vDqKv4Dg2MN7
Discussion