У книги уже есть типы и статус, но типы не проверяют всё. Строка " " — допустимая строка для PHP, хотя как название книги она бесполезна. Нужны правила самого приложения: проверить вход, нормализовать то, что можно поправить, и сообщить о том, что принять нельзя.

Проверяйте данные на границе приложения

Пользовательский ввод, файл и внешний API — границы, за которыми приложение не контролирует формат данных. Проверка должна происходить до создания доменного объекта. Например, название книги можно обрезать от пробелов, а пустое после этого значение отклонить:

<?php
declare(strict_types=1);

function normalizeTitle(string $title): string
{
    $title = trim($title);

    if ($title === '') {
        throw new InvalidArgumentException('Введите название книги.');
    }

    return $title;
}

trim() исправляет случайные пробелы по краям. Пустое название — уже ошибка, которую нужно показать пользователю. Важно не превращать любое неожиданное значение в пустую строку: это скроет источник проблемы.

Исключение — для отказа выполнить обещание

Если функция обещает создать корректную книгу, она может выбросить исключение, когда данные этому правилу не соответствуют:

function parseYear(string $input): int
{
    $year = filter_var($input, FILTER_VALIDATE_INT);

    if ($year === false || $year < 1 || $year > (int) date('Y')) {
        throw new InvalidArgumentException('Укажите реальный год издания.');
    }

    return $year;
}

Здесь результат false означает, что вход не преобразовался в целое число. Не проверяйте результат через if (!$year): год 0 тоже ложный, и причина ошибки станет неясной.

Ловите ошибку там, где можете на неё ответить

В веб-приложении контроллер знает, что надо вернуть форму с подсказкой. Функция разбора года этого не знает, поэтому она лишь сообщает о неверных данных:

try {
    $year = parseYear($yearInput);
    $title = normalizeTitle($titleInput);
    $book = new Book($title, $author, $year);
} catch (InvalidArgumentException $exception) {
    $errorMessage = $exception->getMessage();
}

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

Разделяйте ошибки данных и ошибки системы

  • Неверное название или год: покажите понятное сообщение рядом с формой.
  • Файл не читается: сообщите об общей проблеме, а технические детали запишите в журнал.
  • Ошибка программиста: не маскируйте её под «данные неверны»; пусть она попадёт в журнал и будет исправлена.

Пользователю не нужны пути к серверным файлам и трассировка стека. Но подробная информация нужна разработчику в логах. В производственной конфигурации ошибки не выводят посетителю на страницу.

Проверьте крайние значения

Попробуйте пустое название, год буквами, год в будущем и корректный год. Крайние случаи часто выявляют, что код использует проверку истинности там, где нужна точная проверка, или доверяет типу раньше, чем данные проверены.

Следующая часть научит каталог переживать перезапуск: запишем книги в JSON-файл. Там мы применим эти правила к чтению и сохранению данных.

Часть 9 из 16.

← Часть 8: Enum и readonly в PHP: надёжный статус книги · Часть 10: Сохраняем данные PHP в JSON: первое хранилище каталога →

Документация