Самоучитель: динамические веб-приложения
Глава 4 из 18II. Язык приложения85 минут

Глава 4. Объекты, которые защищают правила

Хороший объект не изображает таблицу базы, а не позволяет приложению оказаться в запрещённом предметном состоянии.

После главы вы сможете
  • выделить инвариант
  • выбрать композицию
  • не превратить контейнер в глобальную переменную

Начинайте с запрещённого состояния

Класс нужен не потому, что проект стал длиннее ста строк. Он оправдан, когда группа значений живёт по общему правилу. Денежная сумма не должна смешивать валюты, заказ не может перескочить из cancelled в paid, email обязан быть нормализован один раз. Конструктор или именованный фабричный метод создаёт только допустимый экземпляр.

Публичные set-методы для каждого поля возвращают объект к роли пассивного контейнера. Лучше выразить операции предметными глаголами: confirm(), cancel(), rename().

Value object и сущность

Value object определяется содержимым и обычно неизменяем: два Email с одинаковым нормализованным адресом эквивалентны. Сущность сохраняет идентичность во времени, даже если меняет состояние. Это различие помогает решить, нужен ли id, где сравнивать объекты и как сохранять их в базе.

readonly уменьшает поверхность случайных изменений, но не делает вложенные объекты неизменяемыми автоматически. Инвариант всё равно принадлежит вашему коду.

Композиция как схема зависимостей

Композиция сценарияЗависимости направлены к предметному сценарию; инфраструктура подключается снаружи.ControllerHTTPUse caseправилоRepositoryконтрактPDO adapterMySQL
Зависимости направлены к предметному сценарию; инфраструктура подключается снаружи.

Интерфейс в правильном месте

Создавайте интерфейс там, где приложению нужна заменяемая граница: хранилище, часы, генератор идентификаторов, отправка уведомления. Интерфейс с одним production-исполнителем всё равно полезен, если unit-тесту нужна детерминированная реализация. Но интерфейс над каждым классом только увеличивает число файлов.

Сценарий формулирует нужные ему методы, а не копирует весь API PDO или внешнего SDK. Такой узкий контракт переживает смену инфраструктуры легче.

Возможности новых веток PHP

PHP 8.4 добавил property hooks и расширил способы описывать доступ к свойствам. PHP 8.5 принёс pipe operator, #[NoDiscard] и другие улучшения типобезопасности. Эти возможности полезны, но не должны быть условием понимания модели. Сначала выразите правило обычным методом, затем применяйте новый синтаксис, если он делает контракт яснее и поддерживаемая версия его допускает.

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

Composition root

Создание PDO, репозиториев, сервисов и контроллеров сосредоточьте в одном месте запуска. Остальной код получает зависимости через конструктор. Service locator и глобальный контейнер скрывают фактический вход класса и делают тест зависимым от порядка инициализации.

Фреймворк может автоматизировать связывание, но мысленная модель остаётся прежней: объект не должен сам искать инфраструктуру.

Практика главы

Смоделируйте задачу со статусами new, active и done. Запретите завершение уже завершённой задачи, вынесите время в Clock и сохранение — в TaskRepository.

Локальный прогресс

Закрепите материал

Отметка, заметка, чек-лист и ответы остаются в localStorage этого браузера и не отправляются в аналитику.

Перелинковка со справочником

Проверка актуальности

  • php.nethttps://www.php.net/releases/8.5/en.phpПервичный источник для актуализации фактов. Адрес приведён как текст и не является активной ссылкой.
  • php.nethttps://www.php.net/manual/en/migration85.phpПервичный источник для актуализации фактов. Адрес приведён как текст и не является активной ссылкой.
  • php-fig.orghttps://www.php-fig.org/psr/psr-4/Первичный источник для актуализации фактов. Адрес приведён как текст и не является активной ссылкой.

Текст и схемы созданы для этого самоучителя без воспроизведения страниц, иллюстраций и листингов приложенной книги. Проверено: .

Данные этого сервиса

Настройки cookie и локальных данных

Аналитика

Текущий статус: не выбран. До согласия обе аналитические системы не загружаются.

Локальные данные

Удаление затрагивает только ключи PHP-сервиса в этом браузере и требует подтверждения.

Политики

Политика конфиденциальности · Политика использования файлов cookie