Имеет ли смысл при разработке на PHP внедрять строго типизированные объекты для запроса и ответа?
Например, если мы знаем, что в action придет $_POST с ключами user_id, post_title, post_text, post_tags[], то можно создать класс типа AddPostRequest, наследуя его от базового класса Request, прописать там поля, валидацию для них, методы доступа.
Или если мы знаем, что в шаблон нужно передать поля status, posts, user, то создаем специальный объект ViewPostsResponse extends Response, прописываем туда хелперы, валидацию, заполняем поля и отправляем в шаблон. Шаблон же знает только про этот объект и все. Своего рода прослойка-контейнер между контроллером и шаблоном.
Этим мы специфицируем формат обмена данными между частями приложения, можем сохранить логику обработки запросов и ответов в этих объектах, более четко разграничиваем роли в приложении.
С другой стороны введением дополнительных сущностей можно усложнить код и привнести дополнительные ошибки. Если их неправильно применять, то можно наоборот размыть границы ролей между частями приложения.
Стоит ли применять подобный подход при разработке на PHP? В других технологиях точно есть типизированные View, скорее всего типизированные запросы тоже есть.
ИМХО, задача реквеста — принять входящие данные (POST/GET/COOKIE и прочие заголовки), инициировать запуск нужного метода контроллера, и вернуть реквест с результатом. Соответственно, вся логика (валидация, запросы к БД и т.д.) должна лежать в контроллере, но не запросе. Request — служебный класс, и его имеет смысл разбивать на подклассы, если возможны различные варианты обработки входящего запроса, но никак не подстраиваться под бизнес-логику.
На счет валидации я с Вами согласен. Иначе пришлось бы предусматривать интерфейс по обмену информацией о результатах валидации между объектом запроса и контроллером. Основная причина применения типизированного запроса — точно определить его структуру и явно задокументировать интерфейс.
Писать классы для req и res — это overengineering. Валидации вполне достаточно, её можно расположить либо в контроллере, либо в модели, зависит от ваших предпочтений.
На мой взгляд — не имеет смысла, реквест должен описывать только логику HTTP и не должен ничего знать о конкретике передаваемых в нём данных. Валидировать запрос должен валидатор после раутинга.
Да. Не должен ничего знать тот самый запрос, который является частью HTTP. Но как только он передается в action — запрос начинают воспринимать именно как объект — контейнер с данными, специфичными для текущего action. Может быть это и не совсем запрос. Можно его назвать и по другому, например ActionDataContainer
А еще можно создать для пущей важности BaseRequest и BaseResponse и там чего-нибудь общее прописать, а потом уже от них наследовать Request и Response, ну и так далее. Можно еще для связи этих объектов сочинить еще какой-нибудь класс-посредник, а для пущей важности сделать объектами еще и все параметры, которые может получать Request, а уже в них для каждого прописать валидацию. Ведь это же ООП, не так ли? ;-)
Просто запрос сам по себе является сущностью. Многие фреймворки выделяют запрос как специальный объект. Его типизация просто дальнейшее развитие этой идеи. Конечно, ООП прежде всего объектная декомпозиция и управление сложностью. Вот и хочется найти баланс, извлекая пользу из применения ООП и не уходя в дебри нагромождения классов.
Вообще-то это была шутка, если кто-то недопонял :) Просто некоторые ООП-программисты грешат тем, что им везде мерещатся классы и они любую сущность готовы превратить в объект.
В шутке ведь всегда есть доля правда. Вот я на эту долю правды и ответил. Вы, кстати, употребляете интересное понятие «ООП-программист», то есть программист, использующий объектно-ориентированное программирование, в отличие от, например, от ФП-программиста, использующего функциональное.
Проблема в том что полиморфизм там корявый будет. Чтоб определить экзепляр какого класса нужно создавать, нужно сначала проанализировать содержимое запроса, что, по вашей конструкции, должно быть сделано в одном из классов потомков.
Классы что отвечают за обработку разных типов запросов — должны быть отделеньми, но прием и анализ, ИМХО — мультиплексор + фильтр = 1, 2 класса (которые не зависят от содержимого пакета).
Вообще что-то есть моментами разумное. Но само по себе типизирование поста это еще не объект, а с валидацией бизнес логики тянет уже на форму. Правда есть случаи когда get-параметры есть, а валидировать их особо не надо (какие-то параметры вьюшки или скажем ?mode=debug), тогда и формы не будет. В общем, может выйти запутанно. Думаю всё что надо это валидация наличия нужных, отсутствия лишних post параметров, это метод базового Request, а наследников и не надо.
А вы смотрели как в популярных фрейморках реализовано?
Кстати, как раз думаю сейчас об этом. В этом есть свои плюсы:
* не надо валидировать данные в контроллере;
* в свою очередь контроллер обзаведётся интерфейсом.
Но и сложность, конечно, существенно увеличивается. Например, когда мы не знаем заранее полный перечень данных, которые нам нужно, и сам этот перечень будет зависеть от тех данных, которые находятся в запросе.
Значит там будет сложный частный случай объекта запроса. Вопрос валидации тоже спорен. Где она должна быть? Я эту проблему поднимал в другом своем вопросе с формами. Вроде бы все склоняются, что валидация должна быть в модели и не должна дублироваться больше нигде. Значит в запрос нужно добавить метод isValid, который будет будет обращаться к модели. Таким образом мы сделаем контроллер еще более тонким, что в принципе не плохо. Такие мысли приходят в голову.