PHP8.1から追加された列挙型(Enum)は、特殊でも一応クラスの一種なので、メソッド・インターフェイスが追加できます。
ただし、やっぱり特殊であることに変わりはなく、『ん?』というところがあるし、普通のクラスと比べてできないこともあります。
メソッドはenumクラスとcaseクラスの両方に追加される
Enumにはメソッドが追加できます。サンプルを見てみましょう。
インターフェイスも追加できるのでついでに使いました。
interface Colorful
{
public function color(): string;
}
enum Car implements Colorful
{
case MATUDA;
case HONDA;
case TOYOTA;
case SUZUKI;
public function color(): string
{
return match($this) {
Car::MATUDA => 'Black',
Car::HONDA => 'Red',
Car::TOYOTA => 'White',
Car::SUZUKI => 'Green',
};
}
}
var_dump(Car::MATUDA->color());
var_dump(Car::HONDA->color());
var_dump(Car::TOYOTA->color());
var_dump(Car::SUZUKI->color());
string(5) "Black"
string(3) "Red"
string(5) "White"
string(5) "Green"
メソッドやインターフェイスはenumクラス(Car)に追加されるように見えますが、caseクラス(各定数オブジェクト)にも追加されます。
これ、普通のクラスではありえないんですが、こう考えれば合点が行きます。
『各caseクラスは、enumクラス(Car)の子クラスだから。』
enumオブジェクトのメソッドはstaticでなければいけない
上記のサンプルでは次のコードはエラーになります。
var_dump(Car::color());
PHP Fatal error: Uncaught Error: Non-static method Car::color() cannot be called statically in /home/vagrant/enum.php:38
Stack trace:
#0 {main}
thrown in /home/vagrant/enum.php on line 38
enumオブジェクト(Car)のメソッドは "::" を使うので、staticメソッドでなければいけません。
サンプルにstaticメソッドを追加しました。
interface Colorful
{
public function color(): string;
public static function names(): array;
}
enum Car implements Colorful
{
case MATUDA;
case HONDA;
case TOYOTA;
case SUZUKI;
public function color(): string
{
return match($this) {
Car::MATUDA => 'Black',
Car::HONDA => 'Red',
Car::TOYOTA => 'White',
Car::SUZUKI => 'Green',
};
}
public static function names(): array
{
return array_column(self::cases(), 'name');
}
}
var_dump(Car::MATUDA::names());
var_dump(Car::MATUDA->names());
var_dump(Car::names());
array(4) {
[0]=>
string(6) "MATUDA"
[1]=>
string(5) "HONDA"
[2]=>
string(6) "TOYOTA"
[3]=>
string(6) "SUZUKI"
}
array(4) {
[0]=>
string(6) "MATUDA"
[1]=>
string(5) "HONDA"
[2]=>
string(6) "TOYOTA"
[3]=>
string(6) "SUZUKI"
}
array(4) {
[0]=>
string(6) "MATUDA"
[1]=>
string(5) "HONDA"
[2]=>
string(6) "TOYOTA"
[3]=>
string(6) "SUZUKI"
}
不思議なことにcaseオブジェクト(定数)は、staticメソッドなのに "->" を使ってもOK。こっちは両方イケるみたい。
これ、普通のクラスだったらエラーだよね?
<?php
class Test {
public static function test() {
return 'test------------';
}
}
var_dump(Test::test());
var_dump(Test->test());
string(16) "test------------"
PHP Fatal error: Uncaught Error: Undefined constant "Test" in /home/vagrant/php8-test.php:10
Stack trace:
#0 {main}
thrown in /home/vagrant/php8-test.php on line 10
やべー、意味がわからん。まぁ static で '->' を使う習慣がないから書かないけど、初心者とかそこまで意識してない人は迷走しそうです。
そうか、caseオブジェクトはインスタンスと考えればいいのか。
<?php
class Test {
public static function test() {
return 'test------------';
}
}
$test = new Test();
var_dump($test::test());
var_dump($test->test());
string(16) "test------------"
string(16) "test------------"
これなら納得。
ちなみに、Enum の標準で付いているメソッドはすべてstaticです。enum, case の両オブジェクトで使えます。
標準メソッドについてはこちらをどうぞ。
PHP公式ドキュメントでは、staticメソッドを使う主な理由はコンストラクタの代わりをさせるためと書いてます。
ちょっと意味が分からない。(サンドウィッチマン風)
enumはstaticなクラス。
(インスタンスではない。)
caseはenumの子クラスのインスタンス。
caseオブジェクト専用のメソッドは 'static' を外す
逆を言えば、staticキーワードを付けなければ、そのメソッドはcaseオブジェクトだけで使えるものになります。
Enumクラスは '::' しか使えないので、staticを外した '->' を使うべきメソッドが自然と使えません。
サンプルでは、color()は、各車メーカーのカラーを返すメソッドです。Enumクラスでは必要ありません。
var_dump(Car::MATUDA->color());
string(5) "Black"
var_dump(Car->color());
PHP Fatal error: Uncaught Error: Undefined constant "Car" in /home/vagrant/enum.php:46
Stack trace:
#0 {main}
thrown in /home/vagrant/enum.php on line 46
var_dump(Car::color());
PHP Fatal error: Uncaught Error: Non-static method Car::color() cannot be called statically in /home/vagrant/enum.php:46
Stack trace:
#0 {main}
thrown in /home/vagrant/enum.php on line 46
普通のクラスと同じことができるようでできない
メソッドやインターフェイスが追加できるので、普通のクラスでできることは全部できそうですが、できないこともあります。
- コンストラクタ・デストラクタは使えない
- 継承は使えない
- プロパティは追加できない
- caseオブジェクト(定数)はクローンできない
- __call, __callStatic, __invoke 以外のマジックメソッドは使えない。(コンストラクタ・デストラクタも使用不可のマジックメソッド。)
ほかに、普通のクラスと同様にできることもいくつかあります。PHP公式ドキュメントを参照ください。
PHP公式ドキュメント