Перечисления PHP 8.1: статусы без произвольных строк

2 мин чтения

Описываем статусы задачи через enum PHP 8.1 и обрабатываем неизвестные значения на входе.

Из внешней строки в известный статус
  1. Входное значениеПолучаем строку или число нужного типа
  2. tryFromСопоставляем с допустимым значением enum
  3. РезультатИспользуем статус или обрабатываем неизвестное значение

Одна опечатка — и вместо pending в базе появляется pendng. Строки удобны для хранения, но допустимые статусы лучше описать в одном месте. В PHP 8.1 для этого есть перечисления. Backed enum связывает каждый вариант со строкой или числом, а tryFrom позволяет разобрать ввод без необработанного исключения.

Описываем допустимые состояния

<?php
enum JobStatus: string {
    case Pending = 'pending';
    case Done = 'done';
}
$status = JobStatus::tryFrom($input);
if ($status === null) {
    throw new InvalidArgumentException('Неизвестный статус');
}
$databaseValue = $status->value;

Предполагается, что input уже получен как строка из проверенного поля запроса. tryFrom возвращает null для неизвестного значения, позволяя сформировать понятную ошибку. Метод from подходит, когда отсутствие соответствия действительно должно приводить к исключению. Случай перечисления и его строковое value — разные значения.

Граница с базой данных

Перечисление в приложении не заменяет ограничения базы. Другой клиент может записать произвольную строку, если схема её допускает. Согласуйте допустимые значения, миграции и обработку старых записей. Не переименовывайте сохраняемое значение без плана перехода: исторические данные не изменятся вслед за PHP-кодом.

Набор вариантов описывает допустимые состояния, но не разрешённые переходы. Возможность перейти из done обратно в pending определяется отдельным правилом. Это правило должно учитывать права пользователя, состояние задачи и требования к журналированию изменений.

Проверяем границы

Проверьте каждый известный статус, пустую строку и незнакомое значение. Посмотрите, как enum передаётся в JSON и в драйвер базы: снаружи нужен ожидаемый формат, внутри — типизированный вариант. И проверьте версию PHP: на 8.0 перечисление из примера не заработает, оно требует 8.1.

Источники и дальнейшее чтение