Menu
Coddy logo textTech

Перечисления (PHP 8.1)

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 59 из 91.

До PHP 8.1 представление фиксированного набора значений, таких как статусы или типы, означало использование констант классов или «магических» строк — оба этих подхода подвержены ошибкам. Enums (перечисления) предоставляют правильный способ определения типа, который может принимать только определенные, заранее заданные значения.

Определите перечисление с помощью ключевого слова enum:

<?php
enum Status {
    case Pending;
    case Active;
    case Completed;
}

$status = Status::Active;
echo $status->name;

Вывод:

Active

Перечисления (Enums) также могут иметь типизированные значения (backed values) — строковые или целочисленные значения, связанные с каждым вариантом. Это полезно при хранении перечислений в базах данных или API:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value;

Вывод:

active

Типизированные перечисления (backed enums) предоставляют метод from() для создания перечисления из его значения, а также метод tryFrom(), который возвращает null вместо того, чтобы выбрасывать ошибку при передаче недопустимых значений:

<?php
$status = Status::from('active');      // Возвращает Status::Active
$invalid = Status::tryFrom('unknown'); // Возвращает null

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

challenge icon

Задание

Легко

Давайте создадим систему управления заказами, которая использует перечисления (enums) для представления статусов заказов безопасным с точки зрения типов способом. Вместо того чтобы полагаться на строки, в которых можно допустить опечатку или которые могут быть недействительными, вы создадите типизированное перечисление (backed enum), которое сопоставляет каждый статус со значением, удобным для базы данных.

Вы организуете свой код в трех файлах:

  • OrderStatus.php — Создайте строковое перечисление (string-backed enum) с именем OrderStatus с четырьмя вариантами (cases):
    • Pending со значением 'pending'
    • Processing со значением 'processing'
    • Shipped со значением 'shipped'
    • Delivered со значением 'delivered'
    Добавьте метод label(), который возвращает понятное человеку описание для каждого статуса:
    • Pending возвращает "Awaiting confirmation"
    • Processing возвращает "Being prepared"
    • Shipped возвращает "On the way"
    • Delivered возвращает "Order complete"
  • Order.php — Создайте класс Order, который использует это перечисление. Подключите файл OrderStatus. Класс должен:
    • Принимать ID заказа (string) и OrderStatus в своем конструкторе, используя продвижение свойств в конструкторе (constructor promotion)
    • Иметь метод getInfo(), который возвращает "Order [id]: [status label]"
    • Иметь метод getStatusValue(), который возвращает строковое значение перечисления (полезно для хранения в базе данных)
  • main.php — Подключите файл Order. Вы получите два входных значения: ID заказа и строку статуса (например, "shipped"). Используйте tryFrom() для безопасного преобразования строкового ввода в перечисление OrderStatus. Если статус валиден, создайте объект Order и выведите две строки:
    • Результат выполнения getInfo()
    • Результат выполнения getStatusValue()
    Если строка статуса невалидна, выведите "Invalid status".

Эта задача демонстрирует, как перечисления обеспечивают безопасность типов — ваш класс Order может принимать только допустимые статусы, а метод tryFrom() позволяет безопасно обрабатывать ввод пользователя, не рискуя получить некорректные значения.

Шпаргалка

Перечисления (Enums) предоставляют типобезопасный способ определения фиксированного набора значений. Определите перечисление с помощью ключевого слова enum:

<?php
enum Status {
    case Pending;
    case Active;
    case Completed;
}

$status = Status::Active;
echo $status->name; // Выводит: Active

Типизированные перечисления (Backed enums) связывают строковые или целочисленные значения с каждым вариантом:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value; // Выводит: active

Используйте from() для создания перечисления из его значения или tryFrom(), который возвращает null для недопустимых значений:

<?php
$status = Status::from('active');      // Возвращает Status::Active
$invalid = Status::tryFrom('unknown'); // Возвращает null

Перечисления могут содержать методы для инкапсуляции связанной логики:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    
    public function label(): string {
        return match($this) {
            self::Pending => 'Awaiting',
            self::Active => 'In Progress',
        };
    }
}

Попробуйте сами

<?php

require_once 'Order.php';

// Чтение входных данных
$orderId = trim(fgets(STDIN));
$statusString = trim(fgets(STDIN));

// TODO: Используйте OrderStatus::tryFrom() для безопасного преобразования строки статуса в перечисление (enum)
// tryFrom() возвращает null, если значение недействительно

// TODO: Если статус валиден, создайте Order и выведите:
// - Результат getInfo()
// - Результат getStatusValue()

// TODO: Если статус невалиден, выведите "Invalid status"

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование