Прежде чем погружиться в рефакторинг кода, я хотел бы сделать шаг назад и пвзлянуть на то, зачем собственно мы хотим использовать некий фреймворк вместо того, чтобы просто писать на чистом PHP. Почему использование фреймворков это хорошая идея, даже если мы хотим набросать простой код ипочему создание фреймворка на основене компонентов Symfony2 это лучше, чем создавать его с нюля?

Я не хочу говорить об очевидных преимуществах использования фреймворков, когда вы работаете над большим проектом с несколькими разработчиками; в Интеренете уже довольно много хороших ресурсов на эту тему

Хотя “приложение”, которое мы написали вчера элементарное, оно все же страдает от некоторых проблем:

Во-первых, если параметр name не передан, то PHP выведет предупреждения, давайте исправим это:

Во-вторых, это приложение не безопастно. Вы можете это представить? Этот наипростейший кусочек кода уязвим для одной из наиболее распространненных сетевых атак, XSS (Cross-Site Scripting). Вот более безопастный вариант:

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

Теперь вы видите, что простой код который мы неписали вначале отнюдь не такой простой, если вы хотети исключить все предупреждения  PHP и сделать код более безопасным.

Также этот код тяжело тестировать. Даже если у вас не много тестов, мне кажется, что написание юнит тестов для этого простойшего кусочка PHP кода не столь интуитивно и будет довольно уродливо. ВОт пример PHPUnit теста для нашего кода:

Если бы наше приложение было бы чуточку больше, у нас было бы гораздо больше проблем. Если вам интересна эта тема, то прочтите Symfony2 versus Flat PHP (перевод) из официально документации.

Если на данном этапе, вы не убеждены что безопастность и тестопригодночть на самом деле 2 хорошие причины чтобы прекратить писать код старым методом и использовать фреймворки, вы можете закончить чтение немедленно и идти на все четыре стороны.

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

Переходим на ООП с использованием компонента HttpFoundation. (Going OOP with the HttpFoundation Component)

Написание веб-кода – это по сути работа с HTTP. И так, фундаментальные принципы фреймворка должны быть сконцентрированы вокрух спецификации HTTP.

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

В PHP запрос представляет собой набор глобальных массивов ($_GET, $_POST, $_FILE,$_COOKIE, $_SESSION…), а ответ генерируется при помощи функций (echo, header,setcookie, …).

Первый шаг к лучшему коду это использование ООП; это и является самоцелью компонента HttpFoundation: он заменяет обычные PHP переменные и функции объектно-ориентированным слоем.

Чтобы воспользоваться этим компонентом, откроем файл composer.json и добавим в него записимость:

Теперь запустим update:

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

Теперь, давайте перепишем наше приложение используя классы Request и Response:

Метод createFromGlobals() создает объект Request на основе текущих глобальных переменных PHP

Метод send() отправляет данные объекта Response обратно клиенту (сначала идут HTTP заголовки, потом контент)

перед вызовом метода send() мы должны вызвать метод prepare() ($response->prepare($request);) чтобы удостовериться, что Response совместим с HTTP спецификацией. Например, если мы получаем страницу методом HEAD, то нужно удалить контент с тела ответа.

Основное отличие от предыдущего кода состоит в том, что у нас есть полный контроль над HTTP сообщением. Вы можете создать абсолютно любой запрос и ответ.

Мы не устанавливали заголовок Content-Type в переписанном коде, так как в объекте Response кодировкой по-умолчанию является UTF-8.

Вместе с классом Request, у вас весь запрос на кончиках пальцев, благодаря приятному и простому API:

Вы также можете имитировать запрос:

С классом Response, вы можете легко настроить ответ:

Чтобы дебажить Response, приведите объект к строковому типу; это вернет HTTP представления ответа (заголовки и содержание)

Последнее, но не менее важное, эти классы, как и любой другой класс в Symfony, были проверены по вопросам безопасности независимой компанией. И, Open-Source проект также означает, что многие другие разработчики по всему миру читают код и уже исправили потенциальные проблемы безопасности. Когда в последний вы заказывали профессиональный аудит безопасности для вашего самодельного фреймворка?

Даже такая простая операция как возвращение IP-адресса клиента может быть небезопасной:

Это работает прекрасно, пока вы не добавите реверс прокси перед сервером на продакшне, в этом случае, вам придется изменить код, чтобы код заработал на обеих ваших машинах (где у вас нет прокси) и вашем сервере:

Используя метод Request::getClientIp() у вас будет рабочий код с первого же дня, вне зависимости от наличия прокси.

Также есть дополнительное преимущество: он является безопасным по умолчанию. Что я подразумеваю под безопасностью? Конечный пользователь может манипулировать значением

$_SERVER[‘HTTP_X_FORWARDED_FOR’] и ему нельзя доверять. Итак, если вы используете этот код в продакшне без прокси-сервера, становится довольно просто взломать вашу систему. Этого не будет с методом getClientIp (), так как вы должны явно указать, что доверяете этому заголовку, вызвав trustProxyData ():

Таким образом, getClientIp() работает надежно в любых обстоятельствах. Вы можете использовать его во всех ваших проектах, независимо от конфигурации, он будет вести себя правильно и безопасно. Это одна из целей использования фреймворка. Если бы вы писали фреймворк с нуля, вам пришлось бы думать обо всех этих нюансах самим. Так почему не использовать технологию которая уже работает?

сли вы хотите узнать больше о компоненте HttpFoundation, вы можете взглянуть на API или прочитать документацию на сайте Symfony.

.

Верите или нет, но теперь у вас есть первый фреймворк. Вы можете остановиться, если хотите, конечно. Использование компонента Symfony2 HttpFoundation уже позволяет писать вам лучший и более тестируемый код. Так же он позволяет писать код быстрее, так как большинство ежедневных проблем уже решены за вас.

На самом деле, проекты, такие как Drupal, используют HttpFoundation; если он работает для них, то, вероятно, будет работать и для вас. Не изобретайте велосипед.

Я чуть не забыл упомянуть об одном дополнительном преимуществе: с помощью компонента HttpFoundation можно добиться лучшего взаимодействия фреймворков и приложений, использующих его (на сегодняшний день Symfony2, Drupal 8, PhpBB 4Silex, Midgard CMS, Zikula … ).