PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 71 · От первого статуса к границам API
UnitEnum и BackedEnum: варианты, внешние коды и проверка входа
Полный API cases/from/tryFrom с различием name/value, строгих типов и неизвестного значения.
Статус заказа должен быть одним из известных вариантов
Внешний код и внутренний статус заказа
Проверяем строку на входе один раз, затем работаем с допустимым вариантом.
- 1$raw = 'paid'↓
Строковое значение из проверенного поля ответа.
- 2is_string($raw)↓
Отделяем текст от массива и прочих неподходящих типов.
- 3OrderState::tryFrom($raw)↓
Ищем объявленный вариант по его внешнему value.
- 4OrderState::Paid↓
Используем объект допустимого состояния. Для неизвестного кода отдельно обрабатываем null.
- 5$state->value
Для сохранения снова получаем строку paid.
Имя Paid отличается от внешнего кода paid. tryFrom не отменяет проверку типа входа.
В обработке заказа встречаются «новый», «оплачен», «отправлен». Обычная строка разрешает и опечатку, и неизвестное значение. Перечисление enum задаёт конечный набор допустимых вариантов. Оно полезно там, где код действительно знает все состояния; постоянно меняющийся каталог товаров лучше хранить в данных.
enum OrderState объявляет тип, а case New — один вариант. OrderState::New выбирает этот вариант через имя типа, без new. Вариант является объектом, его name — строковое имя New. Начнём без внешних скалярных кодов. Метод label() добавляет понятную подпись для человека; match выбирает её по текущему case.
- enum задаёт New и Paid
- OrderState::cases() возвращает оба варианта по порядку
- foreach сохраняет текущий вариант в $state
- $state->name даёт New/Paid, label() — Новый/Оплачен
<?php
declare(strict_types=1);
enum OrderState
{
case New;
case Paid;
public function label(): string
{
return match ($this) { self::New => 'Новый', self::Paid => 'Оплачен' };
}
}
foreach (OrderState::cases() as $state) {
echo $state->name, ': ', $state->label(), "\n";
}
Ожидаемый результат
New: Новый
Paid: Оплачен
Каждый enum автоматически выполняет UnitEnum, который задаёт cases(): array. Метод возвращает все варианты в порядке объявления. name — имя варианта в программе; человеческую подпись задаёт label. Нельзя реализовать UnitEnum обычным классом и получить таким способом собственный enum.
Обычный пользовательский класс не может написать implements UnitEnum/BackedEnum вместо объявления enum. PHP автоматически предоставляет cases любому enum, и переопределить его нельзя. Методы from/tryFrom автоматически добавлены и зарезервированы у backed enum. Pure enum вправе объявить собственные методы с такими именами, но автоматического поиска по value у него нет. Подробнее об остальных ограничениях, методах и сравнениях — полная глава о перечислениях.
BackedEnum: связать вариант с кодом базы данных или API
Внутри приложения хочется проверять OrderState::Paid, а в таблице хранить строку paid. Для этого после имени enum ставят : string или : int, а каждому case назначают уникальное значение соответствующего типа. Такой enum автоматически реализует BackedEnum и UnitEnum. Свойство name содержит имя варианта, value — внешний код.
- Строка "paid" пришла из проверенных данных
- OrderState::from("paid") → вариант OrderState::Paid
- Код работает с вариантом
- Для сохранения $state->value → строка "paid"
<?php
declare(strict_types=1);
enum OrderState: string { case New = 'new'; case Paid = 'paid'; }
$databaseRow = ['id' => 42, 'status' => 'paid'];
$state = OrderState::from($databaseRow['status']);
echo 'Заказ ', $databaseRow['id'], ': ', $state === OrderState::Paid ? 'оплачен' : 'новый', "\n";
echo 'Код для сохранения: ', $state->value, "\n";
Ожидаемый результат
Заказ 42: оплачен
Код для сохранения: paid
BackedEnum расширяет договор UnitEnum: к cases добавляет from/tryFrom и у вариантов есть value. from ищет по скалярному коду, а не по русской подписи или имени Paid. Известная строка из проверенного хранилища даёт конкретный case; повреждённое значение потребует обработки ValueError.
<?php
declare(strict_types=1);
enum Delivery: string { case Pickup = 'self'; case Courier = 'door'; }
$wrong = Delivery::tryFrom('Pickup');
echo $wrong === null ? "API не знает код Pickup\n" : "Код найден\n";
$selected = Delivery::from('self');
echo 'Выбран вариант: ', $selected->name, "\n";
echo 'Отправить в API: ', $selected->value, "\n";
Ожидаемый результат
API не знает код Pickup
Выбран вариант: Pickup
Отправить в API: self
Внутреннее имя case можно выбрать по стилю кода, а внешний value должен соответствовать договору сервиса. from и tryFrom работают с value. Не переименовывайте сохранённые коды без миграционного плана.
name и value доступны для чтения, но не переназначаются. Enum с внешним кодом выбирает один тип на всё перечисление, не int|string по разным case. Типичная миграция — проверять внешний код на границе, а внутрь бизнес-методов передавать конкретный тип enum.
Отделить неизвестное значение от неправильного типа
- Получить сырое поле status
- Проверить, что это строка, а не массив
- tryFrom ищет значение среди разрешённых кодов
- null даёт сообщение о неизвестном статусе
- Найденный case можно передать типизированной операции
tryFrom удобен, когда неизвестный код ожидаем и его нужно показать как ошибку формы. Но он не принимает любые данные без исключений: массив, объект или несовместимый тип всё равно могут вызвать TypeError. Сначала проверьте форму входа, затем ищите вариант. Не превращайте неизвестный платёжный статус в «оплачен» через удобное значение по умолчанию.
<?php
enum OrderState: string { case New = 'new'; case Paid = 'paid'; }
$payload = ['status' => 'cancelled'];
$raw = $payload['status'] ?? null;
if (!is_string($raw)) {
echo "Статус должен быть строкой\n";
} else {
$state = OrderState::tryFrom($raw);
echo $state === null ? "Неизвестный статус\n" : $state->name . "\n";
}
Ожидаемый результат
Неизвестный статус
Проверка типа и проверка множества вариантов — разные этапы. HTTP-обработчик на этом месте вернёт понятную ошибку валидации, а не молча сменит состояние заказа.
<?php
declare(strict_types=1);
enum Priority: int { case Normal = 1; case High = 2; }
echo Priority::from(1)->name, "\n";
try { Priority::tryFrom('1'); }
catch (TypeError $error) { echo "Требуется int\n"; }
Ожидаемый результат
Normal
Требуется int
В strict_types=1 int-backed enum не принимает строку "1". В нестрогом вызове PHP может преобразовать подходящее скалярное значение; это не замена проверке входа. Приведение (int) произвольного текста способно превратить ошибку в 0.
<?php
enum Priority: int { case Normal = 1; case High = 2; }
echo Priority::from('1')->name, "\n";
Ожидаемый результат
Normal
Этот пример специально не содержит declare(strict_types=1). Разница определяется местом вызова. Для предсказуемого API нормализуйте вход по явным правилам, а не стройте проверку на побочных преобразованиях.
Если функции нужен OrderState, передавайте OrderState::Paid или результат проверенного from/tryFrom. Строка paid сама по себе не станет enum при обычной проверке типа параметра. Это граница, которая защищает остальной код от повторения одних и тех же строковых проверок.
Источники и обсуждения
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


