在PHP中,枚举类型是一种非常强大的数据类型,它允许我们定义一组命名的常量。这些常量可以包含方法,也可以实现接口。如果枚举实现了接口,那么其中的条目也能接受接口的类型检测。此外,枚举类型还提供了一些静态方法,这些方法可以在不创建枚举实例的情况下调用。
一、枚举方法
枚举(包括纯粹枚举、回退枚举)还能包含方法, 也能实现 interface。 如果 Enum 实现了 interface,则其中的条目也能接受 interface 的类型检测。
<?php interface Colorful { public function color(): string; } enum Suit implements Colorful { case Hearts; case Diamonds; case Clubs; case Spades; // 满足 interface 契约。 public function color(): string { return match($this) { Suit::Hearts, Suit::Diamonds => 'Red', Suit::Clubs, Suit::Spades => 'Black', }; } // 不是 interface 的一部分;也没问题 public function shape(): string { return "Rectangle"; } } function paint(Colorful $c) { ... } paint(Suit::Clubs); // 正常 print Suit::Diamonds->shape(); // 输出 "Rectangle" ?>
在这例子中,Suit 所有的四个实例具有两个方法: color()、shape()。 目前的调用代码和类型检查,和其他对象实例的行为完全一致。
在回退枚举中,interface 的声明紧跟回退类型的声明之后。
<?php interface Colorful { public function color(): string; } enum Suit: string implements Colorful { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; // 满足 interface 的契约。 public function color(): string { return match($this) { Suit::Hearts, Suit::Diamonds => 'Red', Suit::Clubs, Suit::Spades => 'Black', }; } } ?>
在方法中,定义了 $this 变量,它引用到了条目实例。方法中可以任意复杂,但一般的实践中,往往会返回静态的值, 或者为 $this match 各种情况并返回不同的值。
注意:在本示例中,更好的数据模型实践是再定一个包含 Red 和 Black 枚举值的 SuitColor 枚举,并且返回它作为代替。 然而这会让本示例复杂化。
以上的层次在逻辑中类似于下面的 class 结构(虽然这不是它实际运行的代码):
<?php interface Colorful { public function color(): string; } final class Suit implements UnitEnum, Colorful { public const Hearts = new self('Hearts'); public const Diamonds = new self('Diamonds'); public const Clubs = new self('Clubs'); public const Spades = new self('Spades'); private function __construct(public readonly string $name) {} public function color(): string { return match($this) { Suit::Hearts, Suit::Diamonds => 'Red', Suit::Clubs, Suit::Spades => 'Black', }; } public function shape(): string { return "Rectangle"; } public static function cases(): array { // 不合法的方法,Enum 中不允许手动定义 cases() 方法 // 参考 “枚举值清单” 章节 } } ?>
尽管 enum 可以包括 public、private、protected 的方法, 但由于它不支持继承,因此在实践中 private 和 protected 效果是相同的。
二、枚举静态方法
枚举也能有静态方法。 在枚举中静态方法主要用于取代构造器,如:
<?php enum Size { case Small; case Medium; case Large; public static function fromLength(int $cm): static { return match(true) { $cm < 50 => static::Small, $cm < 100 => static::Medium, default => static::Large, }; } } ?>
仅管 enum 可以包括 public、private、protected 的静态方法, 但由于它不支持继承,因此在实践中 private 和 protected 效果是相同的。