Методы перечислений
Перечисления (как чистые, так и типизированные) могут содержать методы и могут реализовывать интерфейсы.
Если перечисление реализует интерфейс, то любая проверка типа этого интерфейса также примет и все варианты этого перечисления.
<?php
interface Colorful
{
public function color(): string;
}
enum Suit implements Colorful
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
// Выполняет контракт интерфейса.
public function color(): string
{
return match ($this) {
Suit::Hearts, Suit::Diamonds => 'Красный',
Suit::Clubs, Suit::Spades => 'Чёрный'
};
}
// Не часть интерфейса; хорошо.
public function shape(): string
{
return "Rectangle";
}
}
function paint(Colorful $c)
{
/* ... */
}
paint(Suit::Clubs); // Работает
print Suit::Diamonds->shape(); // выведет "Rectangle"
?>
В этом примере каждый из четырёх экземпляров Suit
имеет два метода:
color()
и shape()
.
В вызывающем коде и при проверке типов экземпляры перечисления ведут себя точно так же, как и любой другой экземпляр объекта.
В типизированных перечислениях объявление интерфейса идёт после объявления типа перечисления.
<?php
interface Colorful
{
public function color(): string;
}
enum Suit: string implements Colorful
{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
// Выполняет интерфейсный контракт.
public function color(): string
{
return match ($this) {
Suit::Hearts, Suit::Diamonds => 'Красный',
Suit::Clubs, Suit::Spades => 'Чёрный'
};
}
}
?>
Переменная $this
определена внутри метода и ссылается на экземпляр варианта.
Сложность методов в перечислениях не ограничена, но на практике методы перечислений чаще возвращают статическое значение
или результат обработки переменной $this
выражением match,
чтобы результаты обработки отдельных экземпляров перечисления отличались.
Обратите внимание, в этом примере более хорошей практикой построения данных было бы —
определить тип перечисления SuitColor
со значениями Red и Black и возвращать их вместо строковых литералов.
Однако это усложнило бы пример.
Иерархия в примере логически похожа на следующую структуру классов
(хотя это не настоящий исполняемый код):
<?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 => 'Красный',
Suit::Clubs, Suit::Spades => 'Чёрный'
};
}
public function shape(): string
{
return "Прямоугольник";
}
public static function cases(): array
{
// Недопустимый метод, поскольку определение метода cases() в перечислениях вручную запрещено.
// Смотрите также раздел "Список значений".
}
}
?>
В перечислениях разрешено объявлять общедоступные, закрытые и защищённые методы,
хотя на практике закрытые и защищённые методы эквивалентны,
поскольку наследование не разрешено.