ConFoo 2025

値に依存した列挙型(Backed Enum)

デフォルトでは、列挙型はスカラー値の情報を持っていません。 単なるシングルトンオブジェクトです。 しかし、列挙型の case をデータベースや、 類似のデータストアで読み書きする必要があるケースが多くあります。 よって、ビルトインの (シリアライズ可能であることが自明な) スカラー値を持つ case があると、本質的に役に立ちます。

列挙型にスカラー値を定義するには、以下のようにします:

<?php

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

スカラー値を持つ case を、"Backed Case" と呼びます。 なぜなら、オブジェクトよりもシンプルな値に依存して(Backed)いるからです。 全ての case が Backed Case である列挙型を "Backed Enum" と呼びます。 Backed Enum には Backed Case のみを含めることができます。 Pure Enum には Pure Case だけを含めることができます。

Backed Enum は、整数、または文字列の値を持つことができます。 そして、単一の列挙型が一度に持つことの出来る型はひとつだけです (つまり、int|string のような union 型はサポートしていないということです)。 列挙型がスカラー情報を持つとマークすると、 全ての case はユニークなスカラーの値を明示的に定義しなければいけません。 自動生成されるスカラー値 (例: 整数の連番) は存在しません。 Backed Enum の case の値は、全てユニークでなければいけません。 つまり、ふたつの Backed Enum の case は、 同じスカラー値を持ってはいけないということです。 しかし、定数は case を参照していても構わないので、 別名を作成することはできます。 列挙型と定数 も参照ください。

スカラー値は、リテラルか、リテラルを表す式でなければいけません。 定数や定数式はサポートしていません。 つまり、1 + 1 は許されますが、 1 + SOME_CONST は許されません。

Backed Enum の case は、追加の読み取り専用のプロパティ value を持っています。 これは、Backed Enum の定義で指定された値です。

<?php

print Suit::Clubs->value;
// "C" と表示
?>

value プロパティを強制的に読み取り専用にするため、 そのリファレンスを変数には代入できません。 つまり、以下のようなコードはエラーになります:

<?php

$suit
= Suit::Clubs;
$ref = &$suit->value;
// Error: Cannot acquire reference to property Suit::$value
?>

Backed Enum は内部的に BackedEnum インターフェイスを実装しています。 このメソッドは、以下の2つのメソッドを公開しています:

  • from(int|string): self スカラー値を受け取り、対応する Enum の case を返します。 対応する case がない場合は、 ValueError がスローされます。 このメソッドは、入力のスカラー値が信頼でき、 存在しない enum の値はアプリケーションを停止すべきエラーとみなせる場合に役立ちます。
  • tryFrom(int|string): ?self スカラー値を受け取り、対応する Enum の case を返します。 対応する case がない場合は、null を返します。 このメソッドは、入力のスカラー値が信頼できない場合で、 呼び出し側が独自のエラーハンドリングや、 デフォルト値のロジックを実装したい場合に役立ちます。

from()tryFrom() メソッドは、標準の 弱い/強い 型付けのルールに従います。 弱い型付けのルールでは、整数または文字列を受け入れ、 システムは値をそれに従って自動変換します。 厳密な型付けモードの場合、文字列型の Backed Enum に整数値を渡す (またはその逆をする) と、TypeError が発生します。 float についても、全ての場合に同じ型付けのルールに従います。 それ以外の型については、どちらのモードでも TypeError が発生します。

<?php

$record
= get_stuff_from_database($id);
print
$record['suit'];

$suit = Suit::from($record['suit']);
// 不正なデータを渡すと、次のようなエラーが発生 -> ValueError: "X" is not a valid scalar value for enum "Suit"
print $suit->value;

$suit = Suit::tryFrom('A') ?? Suit::Spades;
// 不正なデータに対しては null を返すので、Suit::Spades が代わりに使われます。
print $suit->value;
?>

Backed Enum において、手動で from()tryFrom() メソッドを定義すると、 致命的なエラーが発生します。

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top