PHP 8.6.0 Beta 1 is available for testing

Методы перечислений

Перечисления (как чистые, так и типизированные) могут содержать методы и могут реализовывать интерфейсы. Если перечисление реализует интерфейс, то любая проверка типа этого интерфейса также примет и все варианты этого перечисления.

<?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)
{
 print $c->color() . "\n";
}
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() в перечислениях вручную запрещено.
 // Смотрите также раздел "Список значений".
 }
}

В перечислениях разрешено объявлять общедоступные, закрытые и защищённые методы, хотя на практике закрытые и защищённые методы эквивалентны, поскольку наследование не разрешено.

Нашли ошибку?

ИнструкцияИсправлениеСообщение об ошибке
+Добавить

Примечания пользователей 1 note

up
25
iloveyii at yahoo dot com
3 years ago
Just to complete the function shape in the above neat example:
<?php
interface Colorful
{
 public function color(): string;
}
enum Suit implements Colorful
{
 case Hearts;
 case Diamonds;
 case Clubs;
 case Spades;
 // Fulfills the interface contract.
 public function color(): string
 {
 return match($this) {
 Suit::Hearts, Suit::Diamonds => 'Red',
 Suit::Clubs, Suit::Spades => 'Black',
 };
 }
 // Not part of an interface; that's fine.
 public function shape(): string
 {
 return match($this) {
 Suit::Hearts => '❤️', 
 Suit::Diamonds => '💎', 
 Suit::Clubs => '♣️', 
 Suit::Spades => ' ♠️'
 };
 
 }
}
echo Suit::Diamonds->shape();
echo PHP_EOL;
echo Suit::Clubs->shape();
+Добавить

AltStyle によって変換されたページ (->オリジナル) /