В этой статье реализован шаблон Beginner.
Иногда вы должны сделать шаг назад от дискуссий о связях, сплоченности, шаблонах и катах, чтобы научить тех из нас, кто обладает процедурным мышлением. В этой статье я надеюсь дать некоторые начальные советы для членов сообщества PHP, которые готовы отказаться от концепции OneSingleProcedure (TM), чтобы охватить объектный мир. В частности, перечислить некоторые специфические проблемы, с которыми сталкиваются стандартные приложения PHP и которые следует учитывать при реинжиниринге существующей системы или создании новых объектов; и следить за (единичной) тестируемостью, которая значительно улучшается при введении объектов поверх процедур или просто спагетти.
OneSingleProcedure (TM)
PHP-программист старого стиля, когда сталкивается с новой функцией, пишет такой вид скрипта:
<?php $connection = mysql_connect(...); // not really different with PDO $parameter = $_GET['name'] ? $_GET['name'] : ''; if (!validate($parameter)) { echo "<p>Error!</p>"; exit(); } mysql_query("INSERT INTO ... "); echo "<p>Success!</p>";
Суть критики заключается не в том, что mysql _ * () небезопасен, а в том, что этот скрипт сочетает в себе множество различных проблем, с которыми PHP-программисты часто сталкиваются, и которые они должны научиться разделять:
- домен HTTP: параметры GET и POST, заголовки и, соответственно, распечатка ответа в UTF-8
- доступ к базе данных (и источнику данных в целом): подключения, запросы или получение данных из веб-служб
- логика домена, такая как валидация и код приложения
Я не предлагаю строить гексагональную архитектуру за день, но применяю базовую объектно-ориентированную декомпозицию, чтобы превратить этот типичный сценарий в реальный сценарий объектов, поставленных на сцену для общения друг с другом.
декомпозиция
Разложение — это нож, который мы используем, чтобы разрезать объект для анализа на множество частей и собрать его вместе, после того, как разбираемся в его частях. Это Motorcycle Maintenance 101: применительно к коду это может привести к моделированию проблемы с несколькими типами базовых объектов:
- E / R моделирование приводит нас к разделению проблемы на таблицы базы данных и их строки. Это то, что разработчики PHP обычно являются экспертами.
- Процедурная декомпозиция (сверху вниз) декомпозирует OneSingleProcedure (TM) на более мелкие, которые, в свою очередь, состоят из нескольких вызовов функций. Обычно эта декомпозиция выполняется для извлечения кода для повторного использования, как в методе validate (), который мы видели ранее, и строго основана на времени: каждая подпрограмма является шагом для выполнения.
- Разложение Парнаса , которое мы должны пытаться применять в объектах и классах, основано на сокрытии информации: каждая часть скрывает проектное решение или техническую проблему; эти части могут индивидуально измениться в будущем, не затрагивая целое, или могут быть реинжинирированы сами по себе, когда запрос на изменение приведен в соответствие с существующей декомпозицией.
Таким образом, в случае нашего сценария есть несколько проблем, которые мы могли бы разделить на объекты (и в более крупных случаях на слои). Проблема с декомпозицией базы данных состоит в том, что схема приобретает исключительно важное значение, и логика фактически исчезает. Вместо этого процедурная декомпозиция имеет дефект, заключающийся в том, что у вас есть только одна ось декомпозиции в отношении того, где выровнять подпрограммы: время.
Но я просто хотел вставить строку в таблицу сообщений !
Нет, ты не сделал; ты хотел:
- отобразить некоторые входные данные HTTP, такие как текстовые и двоичные файлы, в набор структур данных в памяти, таких как массивы и другие переменные.
- Проверьте этот ввод, чтобы проверить его соответствие правилам домена (например, «Текст сообщения не должен быть пустым»).
- Измените постоянное состояние приложения, вставив новую строку.
- Создайте HTML-ответ для браузера пользователя.
Эти четыре проблемы ( конкретно говоря, HTTP, правила домена, SQL и HTML ) никогда не должны смешиваться в одном файле; строгое разделение является облегчающим (но не достаточным) условием для простоты обслуживания и изменения существующего кода без головной боли. Неудача разделения этих концепций приводит к невозможности модульного тестирования кода изолированно.
<?php class ForumPostsTest extends PHPUnit_Framework_TestCase { public function testAPostIsSavedAfterValidationAndAParagraphResponseIsShown() { // apart from the overly long test name, what code could I write in order to test newpost.php? } }
Вывод
Как правило, имейте в виду, что если вы пишете любые два элемента из списка HTTP, validate (), SQL, HTML в одном и том же исходном файле, что-то пошло не так. Требуется время, чтобы забыть процедурное мышление и начать разлагать обязанности вместо данных; эмуляция существующих архитектур и их расслоение — это не точка прибытия, а хорошее начало для написания чего-то более понятного, чем сценарий на 4000 строк.