こんにちは。よっしーです(^^)
今日は、PHPの列挙型(Enum)についてご紹介します。
背景
PHP8.2を利用したAPIを開発しているときに列挙型(Enum)を利用したので、そのときの調査内容を備忘としてのこしました。
こちらのサイトを参考にしています。
列挙型(Enum)オブジェクトとの違い
列挙型(Enum)はクラスとオブジェクトに基づいて構築されていますが、すべてのオブジェクト関連の機能をサポートしているわけではありません。特に、列挙型のケースは状態を持つことが禁止されています。
以下は、列挙型がサポートしないオブジェクト関連の機能についての詳細です:
- コンストラクタとデストラクタは許可されていません。
- 継承はサポートされていません。列挙型は拡張または拡張されることはできません。
- 静的プロパティまたはオブジェクトプロパティは許可されていません。
- 列挙型ケースのクローンはサポートされていません。ケースはシングルトンインスタンスである必要があるためです。
- 以下のマジックメソッド以外のマジックメソッドは許可されていません。
- 列挙型は常に使用される前に宣言する必要があります。
一方、次のオブジェクト関連の機能は使用可能で、他のオブジェクトと同様に動作します:
- パブリック、プライベート、およびプロテクテッドメソッド。
- パブリック、プライベート、およびプロテクテッド静的メソッド。
- パブリック、プライベート、およびプロテクテッド定数。
- 列挙型は任意の数のインターフェースを実装できます。
- 列挙型およびケースには属性を付与することができます。
さらに、列挙型ケースは new
を使用して直接インスタンス化することはできず、ReflectionClass::newInstanceWithoutConstructor() を使用してもインスタンス化することはできません。どちらもエラーになります。
$clovers = new Suit();
// エラー: 列挙型 Suit をインスタンス化できません
$horseshoes = (new ReflectionClass(Suit::class))->newInstanceWithoutConstructor()
// エラー: 列挙型 Suit をインスタンス化できません
列挙型(Enum)ケースのリスト
純粋な列挙型(Pure Enums)およびバックアッド列挙型(Backed Enums)の両方は、内部インターフェースとしてUnitEnumという名前のインターフェースを実装しています。UnitEnumにはstaticメソッドであるcases()が含まれています。cases()メソッドは、宣言の順序で定義されたすべてのケースのパックされた配列を返します。
Suit::cases();
// これにより、[Suit::Hearts, Suit::Diamonds, Suit::Clubs, Suit::Spades] が生成されます
列挙型に対してcases()メソッドを手動で定義すると、致命的なエラーが発生します。手動でcases()メソッドを定義することは許可されていないためです。
列挙型(Enum)シリアライズ
列挙型(Enum)はオブジェクトとは異なる方法でシリアル化されます。具体的には、列挙型ケースの名前を指定する新しいシリアル化コード “E” が存在します。その後、逆シリアル化ルーチンはその名前を使用して既存のシングルトン値に変数を設定できます。これにより、次のようなことが確実に保証されます:
Suit::Hearts === unserialize(serialize(Suit::Hearts));
print serialize(Suit::Hearts);
// E:11:"Suit:Hearts";
逆シリアル化時に、シリアル化された値に一致する列挙型とケースが見つからない場合、警告が表示され、false が返されます。
純粋な列挙型がJSONにシリアル化された場合、エラーが発生します。バックアッド列挙型がJSONにシリアル化された場合、適切な型でスカラー値のみが表現されます。両方の挙動はJsonSerializableを実装することで上書きできます。
print_r()
の場合、列挙型ケースの出力はオブジェクトとは異なり、混乱を最小限に抑えるために若干異なります。
enum Foo {
case Bar;
}
enum Baz: int {
case Beep = 5;
}
print_r(Foo::Bar);
print_r(Baz::Beep);
/* 以下のように出力されます
Foo Enum (
[name] => Bar
)
Baz Enum:int {
[name] => Beep
[value] => 5
}
*/
これにより、列挙型ケースが print_r()
によって表示される形式がわかりやすくなります。
おわりに
今日は、PHPの列挙型(Enum)についてご紹介しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント