ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHP8.1, 列挙型(Enum)にメソッド・インターフェイスが追加できる。継承はできない。

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

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公式ドキュメントを参照ください。

前の投稿
PHP8.1, 定数値を入れる列挙型(Enum)。Backed Enum と言うらしい。
PHP8.1, 列挙型(Enum)に定数(const)が追加できる。使いみちがなさそうである。
次の投稿
コメントを残す

*