В строковом поле статуса можно случайно сохранить readed вместо read. Программа не поймёт, что это опечатка, пока не встретит её в неожиданной ветке. Перечисление enum делает допустимые варианты частью кода и помогает PHP проверить их раньше.
Объявляем статус как enum
Создайте src/ReadingStatus.php:
<?php
declare(strict_types=1);
namespace App;
enum ReadingStatus: string
{
case Planned = 'planned';
case Reading = 'reading';
case Read = 'read';
}
В строковом перечислении у каждого варианта есть строковое значение для хранения или обмена данными. Внутри PHP мы передаём не произвольный текст, а ReadingStatus::Read. Попытка создать несуществующий вариант будет заметна.
Используем enum в модели
Обновите модель книги: статус получит контролируемый тип, а объект перестанет меняться после создания:
<?php
declare(strict_types=1);
namespace App;
final readonly class Book
{
public function __construct(
private string $title,
private string $author,
private int $year,
private ReadingStatus $status = ReadingStatus::Planned,
) {
if (trim($title) === '') {
throw new \InvalidArgumentException('У книги должно быть название.');
}
}
public function title(): string { return $this->title; }
public function author(): string { return $this->author; }
public function year(): int { return $this->year; }
public function status(): ReadingStatus { return $this->status; }
}
Readonly-классы появились в PHP 8.2. Их объявленные свойства должны иметь тип и не могут быть изменены после инициализации. Для обычного каталога это удобно: запись создаётся с согласованными значениями и дальше передаётся между функциями без риска, что её статус незаметно поменяют в середине операции.
$book = new Book(
title: 'Дюна',
author: 'Фрэнк Герберт',
year: 1965,
status: ReadingStatus::Read,
);
if ($book->status() === ReadingStatus::Read) {
echo 'Книга прочитана';
}
Readonly — не глубокая заморозка всего объекта
Readonly запрещает повторно присвоить само свойство. Если свойство содержит изменяемый объект, его внутреннее состояние может измениться отдельно. В нашей модели свойства — строки, число и enum, поэтому этого нюанса пока не возникает. Для вложенных объектов правила проектируют отдельно.
Поддержка нескольких версий
Enums появились в PHP 8.1, readonly-классы — в PHP 8.2. Если проект должен работать на PHP 8.1, используйте readonly-свойства вместо readonly-класса. Для нового курса ориентируемся на поддерживаемую ветку PHP 8.5, но важно понимать минимальную версию синтаксиса каждого элемента.
В PHP 8.5 также появились функции array_first() и array_last() для получения первого и последнего значения массива; если в проекте поддерживается более ранняя ветка, оставляйте совместимый вариант с проверкой массива. В основной модели каталога это не нужно, поэтому не будем добавлять новую функцию только ради короткой записи.
Теперь книга имеет контролируемые данные. В следующей части научимся сообщать о неверной записи и отделять ошибки пользователя от настоящих сбоев приложения.
Навигация по курсу
Часть 8 из 16.
← Часть 7: Классы и объекты PHP: создаём модель книги · Часть 9: Валидация и исключения PHP: отклоняем неверные данные →
0
7