Перечисления (Enums) в PHP 8.1
Перечисления в PHP 8.1 позволяют описать ограниченный набор значений как отдельный тип. Они усиливают проверку типов, упрощают поддержку кода и позволяют добавлять методы и статические фабрики. Используйте базовые enums для именованных вариантов и поддерживаемые (backed) enums, если нужно связать каждое значение со строкой или целым числом.

Что делают перечисления
Перечисления полезны, когда нужно работать с фиксированным набором связанных значений. Они подходят для представления мастей карт, типов транспортных средств или статусов заказа. В PHP перечисления имеют черты классов: их можно использовать в подсказках типов (type hinting), добавлять методы и статические вспомогательные функции.
Определение термина
- Перечисление (enum) — именованный тип, значение которого ограничено фиксированным набором кейсов. Кратко: enum = ограниченный набор значений, доступных в коде.
Базовые перечисления
Базовые enums в PHP не имеют связанного скалярного значения. Их значения — имена кейсов.
enum Season
{
case Spring;
case Summer;
case Autumn;
case Winter;
}Обращение к конкретному значению выполняется через синтаксис EnumTypeName::CaseName:
// Ссылка на значение
$w = Season::Winter;
// Проверка
$favourite = Season::Summer;
if ($favourite == get_current_season()) {
echo "It's my favorite season!";
}Подсказки типов позволят ограничить параметры и возвращаемые значения конкретным перечислением. Это уменьшает количество ошибок и делает код предсказуемее:
function get_current_season(): Season
{
$day = date("z"); // номер дня в году, 0..365
if ($day < 59 || $day > 333) return Season::Winter;
if ($day < 151) return Season::Spring;
if ($day < 243) return Season::Summer;
return Season::Autumn;
}Если функция вернёт не значение Season, PHP выбросит TypeError.
Поддерживаемые перечисления
Backed enums — это перечисления, у которых у каждого кейса есть связанное скалярное значение: int или string. Тип нужно объявить явно.
enum Month: int
{
case Jan = 1;
case Feb = 2;
// ...
}Доступ к базовому значению осуществляется через свойство value:
echo Month::Jan->value; // выведет 1Есть удобный статический метод from для преобразования скалярного значения в enum:
var_dump(Month::from(2)); // вернёт Month::Feb или выбросит ValueErrorИспользуйте backed enums, когда данные приходят извне (JSON, БД, HTTP) и нужно хранить сопоставимое значение.
Методы в перечислениях
Перечисления могут содержать методы и поведение. Внутри метода можно использовать $this, как в объекте. Это полезно для вычислений, связанных с конкретным кейсом.
enum Month: int
{
case Jan = 1;
case Feb = 2;
case Mar = 3;
case Apr = 4;
case May = 5;
case Jun = 6;
case Jul = 7;
case Aug = 8;
case Sep = 9;
case Oct = 10;
case Nov = 11;
case Dec = 12;
/* Внимание: обработка високосного года не реализована */
public function daysInMonth(): int
{
if ($this == Month::Feb) return 28;
if (in_array($this, [Month::Apr, Month::Jun, Month::Sep, Month::Nov])) return 30;
return 31;
}
public static function random(): Month
{
return Month::from(rand(1, count(Month::cases())));
}
}Статические методы полезны для фабрик, генерации случайного значения или валидации.
Когда перечисления не подходят
Important
- Если набор значений меняется часто и динамически (например, администратор добавляет варианты через UI), enum не подойдёт — лучше использовать запись в БД или конфиг.
- Когда к каждому значению нужно хранить большое количество связанных данных (много полей), удобнее использовать класс записи/сущность или Value Object.
- Если требуется множественное сочетание флагов (биты), рассмотрите битовые флаги или отдельные объекты, а не enum.
Альтернативные подходы
- Константы в классе (class constants) — если нужна простая группировка без методов.
- Value Object — когда требуется поведение и связанные данные на экземпляр.
- Таблица в базе данных — если набор изменяем пользователем.
- Битовые маски — для множества флагов, где значения комбинируются.
Ментальные модели и эвристики
- Enum = именованная группа вариантов. Если можно перечислить все варианты заранее — используйте enum.
- Backed enum = enum, который сериализуется / маппится в БД или в API.
- Методы в enum = поведение, относящееся только к конкретному варианту.
Факто-бокс
- Минимальная версия PHP с поддержкой: 8.1
- Поддерживаемые типы для backed enum: int, string
- Полезные методы: ->value, ::from(), ::cases()
Чек-лист для ролей
Разработчик
- Решить, статичен ли набор значений.
- Выбрать базовый или backed enum.
- Добавить unit-тесты для методов enum.
- Использовать подсказки типов в сигнатурах функций.
Код-ревьювер
- Проверить, не скрывает ли enum бизнес-логику, которую лучше вынести в сервис.
- Убедиться, что from обрабатывает неверные входные данные.
Оператор/DevOps
- Проверить минимальную версию PHP в окружениях: >= 8.1.
- Убедиться, что миграции и сериализация совместимы с сохранёнными значениями.
Критерии приёмки
- Unit-тесты покрывают все кейсы enums и методы.
- Для backed enum проверки на корректную сериализацию/десериализацию в БД.
- Функции с hint: возвращают только значения enum, иначе TypeError.
Чит-карта и примеры
Быстрые сниппеты для часто встречающихся задач:
// Перебор всех кейсов
foreach (Month::cases() as $m) {
echo $m->value . " - " . $m->name . "\n";
}
// Конвертация из строки/числа
try {
$m = Month::from(12);
} catch (ValueError $e) {
// обработка некорректного значения
}
// Использование в подсказках типов
function handleMonth(Month $month): void {
// ...
}Совместимость и миграция
- Требуется PHP 8.1+. Для старых версий используйте класс-константы или пакеты-полифилы, но поведение будет ограничено.
- При миграции данных в БД заранее проверьте соответствие значений (для backed enum).
- Если сериализация JSON используется в API, документируйте, что приходит: имя кейса или его value.
Короткое руководство по дизайну
- Выясните, статичен ли набор значений.
- Если да, решите: нужен ли скалярный эквивалент для хранения или передачи.
- Используйте методы enum для логики, которая зависит только от значения.
- При необходимости добавьте статические фабрики и валидаторы.
Краткое резюме
Перечисления в PHP 8.1 упрощают работу со статичными наборами значений, повышают читаемость и безопасность типов. Backed enums удобны для сериализации и хранения, методы внутри enum позволяют инкапсулировать поведение, связанное с конкретным вариантом. Выбирайте enum, когда набор значений стабилен и заранее известен.
Похожие материалы
Вторая временная зона в Google Календаре
Как изменить первый день недели в Google Календаре
Отключить события из Gmail в Google Календаре
Включить тёмный режим в Google Календаре
Тайм‑блокинг коммуникаций для продуктивной работы