PHP8.1から列挙型が追加されました。Enumという特殊なクラスです。
列挙型は定数をまとめたもの。Javaにはすでにあるんですが、そのPHP版といったところです。
既存のクラスで同じことができなくもないんですが、定数の集合を明示することで読みやすくなります。
定数値をもたない定数が定義できる
Enumは特殊なクラスです。classキーワードの代わりに enum を使います。
enum Color
{
case Red;
case Green;
case Blue;
case Yellow;
case White;
case Black;
}
定数値が不要で定数名だけで定義できます。
これは便利。たんに区別するための定数だけが必要で値はどうでもいいなんてことはよくあります。
(定数名を値に入れたり。)
Enumは定数値がなくてもいいので使い勝手が良さそう。
Enumはシングルトンクラス
Enumはシングルトンなので1つのインスタンスしか持てません。各定数を参照するときは "::" を使います。
$val = Color::Red;
var_dump($val);
enum(Color::Red)
ただし、enum自体のオブジェクト(Color)は参照できません。(変数に代入できない。)
$val = Color;
PHP Fatal error: Uncaught Error: Undefined constant "Color" in /home/vagrant/enum.php:14
caseの定数もクラスオブジェクト
caseキーワードで定義する定数もクラスです。caseオブジェクトは nameプロパティをもち、定数名を取得することも可能。
$val = Color::Red;
var_dump($val->name);
string(3) "Red"
'->' を見ても分かるように、caseクラスはインスタンスなので、Enumクラスとちがって変数に代入するできます。
定数の比較
厳密な比較演算子(===, !==)で定数の比較ができます。
$val = Color::Red;
if (Color::Red === $val ) {
var_dump(true);
} else {
var_dump(false);
}
$val = Color::Yellow;
if (Color::Red !== $val ) {
var_dump(true);
} else {
var_dump(false);
}
bool(true)
bool(true)
instanceof 演算子はちょっと複雑で、caseオブジェクトは使えません。
$val = Color::Red;
if ( $val instanceof Color::Red ) {
var_dump(true);
} else {
var_dump(false);
}
PHP Parse error: syntax error, unexpected identifier "Red", expecting variable or "$" in /home/vagrant/enum.php on line 14
ただし、enumオブジェクトは可能。
$val = Color::Red;
if ( $val instanceof Color ) {
var_dump(true);
} else {
var_dump(false);
}
$val = Color::White;
if ( $val instanceof Color ) {
var_dump(true);
} else {
var_dump(false);
}
bool(true)
bool(true)
enum自体のクラスはデータ型に使えるけどcaseクラスは使えません。
instanceofは、どのEnumを使ってるか? には使えるけど、定数比較では使えません。
結果を見る限り、caseクラスは、enumクラスの子クラスのようです。
関数の引数で渡す
Enumの定数(caseオブジェクト)は変数代入ができるので、関数の引数で渡すこともできます。
function test(Color $color) {
var_dump($color);
}
test(Color::Red);
enum(Color::Red)
instanceofの結果でも分かるように、caseクラスはデータ型には使えないので、関数のパラメータの型にはenumクラスじゃないと使えません。
function test(Color::Red $color) {
var_dump($color);
}
test(Color::Red);
PHP Parse error: syntax error, unexpected token "::", expecting variable in /home/vagrant/enum.php on line 13
また、enumクラスのオブジェクトは変数に代入できないので、関数のパラメータに渡すこともできません。
function test(Color $color) {
var_dump($color);
}
test(Color);
PHP Fatal error: Uncaught Error: Undefined constant "Color" in /home/vagrant/enum.php:17
Stack trace:
#0 {main}
thrown in /home/vagrant/enum.php on line 17
Enum のキャスト
Enumは特殊でもクラスには変わりはないので、object型にキャストすることができます。
データの破損もありません。
$val = (object)Color::Red;
var_dump($val);
var_dump($val->name);
enum(Color::Red)
string(3) "Red"
配列にキャストすることも可能。
$val = (array)Color::Red;
var_dump($val);
array(1) {
["name"]=>
string(3) "Red"
}
上記以外の型にはキャストできません。
cases() で定数一覧を取得
enumクラスには唯一メソッドがあります。定数一覧を取得します。
var_dump(Color::cases());
array(6) {
[0]=>
enum(Color::Red)
[1]=>
enum(Color::Green)
[2]=>
enum(Color::Blue)
[3]=>
enum(Color::Yellow)
[4]=>
enum(Color::White)
[5]=>
enum(Color::Black)
}
リストの中身は文字列ではなくcaseクラスのオブジェクト。定数そのもの。
enumクラスは内部で、cases() を定義したUnitEnum インターフェイスをimplementsしているので、すべての列挙型にはcases()が実装されてます。
cases()はオーバーライドできません。
PHP公式ドキュメント
Enumも一種のクラスなので、自作のメソッド、インターフェイスの実装から、定数の定義までできます。traitの実装もできる。
PHP8.1以降しか動かない
Enum(列挙型)はPHP8.1に導入された機能なので、当然ですがPHP8.0以前は使えません。エラーになります。
PHP Parse error: syntax error, unexpected identifier "Color" in /home/vagrant/enum.php on line 3
PHP Parse error: syntax error, unexpected 'Color' (T_STRING) in /home/vagrant/enum.php on line 3
下位互換はまったくないので、PHP8.1以上で運用するというかなり限定的なものじゃないかぎり使えないな。
下位互換用に自作のクラスで似たようなものを作れなくもないけど、その作業がめんどくさい。
Enum を使うのは、PHP8.1以上が主流になるまで待ったほうがいいかもしれない。
Enumには2種類がある
今回は定数値のない定数を定義しましたが、定数値を定義するEnumもあります。Backed Enum と言います。
それに対して、定数値のない Enum のことを Pure Enum と言います。
また、定数値があるcaseを Backed Case、定数値がないものを Pure Case と言います。
PHP公式ドキュメント