Полный цикл разработки php-фреймворка

Полный цикл разработки php-фреймворка

Эта статья - первая в цикле материалов, предназначенных для тех, кто хочет шаг за шагом, последовательно освоить процесс разработки php-приложения. Мы с вами создадим его с нуля и затем будем развивать, добавляя абстракции. Также этот цикл будет полезен тем, кто хочет:

  • Разобраться, как работают и взаимодействуют symfony компоненты.
  • Понять, как функционируют инструменты автоматизации и как использовать их для повышения эффективности своего повседневного воркфлоу.
  • Проанализировать low level архитектуры современного веб-приложения.
  • Поэкспериментировать, создавая свой фреймворк.
  • Определить полезные для собственной практики подходы для рефакторинга легаси-приложения.
  • Узнать, как создавать юнит-тесты и функциональные тесты php-приложения.

Вдохновлено циклом "Create your Own Framework" от Fabien Potencier. По сути, я предлагаю разбор этого курса, однако с бóльшим акцентом на инструменты и работу с реальным контентом.

Установка окружения

В работе нам понадобятся git, php, nodejs, grunt, bower и less. Среду разработки вы можете выбрать на свое усмотрение, я использую phpstorm или atom.

Установка окружения для OS X

Для Brew:

brew install php56 git nodejs  
npm install -g less grunt bower  

Установка окружения для Linux

Рассмотрим вариант для Ubuntu, в других репозиториях практически идентично:

add-apt-repository ppa:ondrej/php5  
apt-get update  
apt-get install php5 git nodejs  
npm install -g less grunt bower  

Установка окружения для Windows

  1. Установить xampp
  2. Добавить php в path своего окружения.  Это нужно для того, чтобы Windows мог напрямую обращаться к бинарникам php.
  3. Скопировать путь к каталогу xampp\php (в зависимости от того, куда вы его установили, путь, естественно, будет различаться. Предположим, вы установили его в корень D:, тогда путь будет, соответственно - D:\xampp\php.
  4. Правый клик по «Мой компьютер» -> «Свойства» и отправляемся сюда: Обновление path в windows В нижнем окошке находим Path и нажимаем "редактировать". В самый конец строки нужно дописать через ; наши пути. Выглядеть это должно следующим образом - то;что;уже;было;D:\xampp\php;D:\xampp\mysql
  5. Ставим гит. При установке важно выбрать следующий вариант, чтобы установщик сам обновил ваш path:

Выбор варианта установки git с обновлением path

Ставим nodejs

Просто скачиваем Windows Installer (.msi), соответствующий разрядности вашей системы, и производим установку. Главное здесь - ничего не менять на шаге выбора пакетов.

  1. Ставим Grunt — инструмент для сборки javascript проектов.
  2. В консоли пишем npm instal -g grunt-cli.
  3. Ставим Bower — пакетный менеджер для клиентского javascript-a.
  4. В консоли пишем npm instal -g bower.
  5. Ставим Less — препроцессор для css.
  6. В консоли пишем npm install -g less.

Проверяем, всё ли в порядке

Открываем консоль (для windows msysgit или power shell), поочередно пишем php -v, git --version, node -v, после чго должны вывестись установленные версии.

Создаем простое приложение

  1. Для начала создадим каталог:
cd /your/work/place  
mkdir feedlerapp  
cd feedlerapp  

2. Здесь разместим наш индекс-файл для вебсервера:

// index.php
echo 'Hello, World!';  

3. Запустим встроенный в php веб-сервер

$ php -S 127.0.0.1:8999

4. Перейдем на 127.0.0.1:8999 и увидим результат выполнения нашего скрипта - страницу приветствия.

Добавляем использование GET параметра

Модифицируем наш скрипт: будем передавать имя для вывода, используя printf

// index.php
$input = $_GET['name'];
printf('Hello %s', $input);  

Перейдем на 127.0.0.1:8999?name=Anna и увидим Hello, Anna!.

Проблемы с безопасностью

Уже на этой стадии в нашем приложении проявляются несколько проблем:

  • если не передавать GET параметр, пользователь увидит предупреждение php о недостающем аргументе. Чтобы это исправить, зададим значение по умолчанию
// index.php
$input = isset($_GET['name']) ? $_GET['name'] : 'World';
printf('Hello %s', $input);  

Теперь, когда GET параметр name не передается, мы используем по умолчанию строку World.

  • Этот участок уязвим к XSS. Чтобы это исправить, нам нужно, во-первых, передавать header с четким описанием типа контента и его кодировки, а во-вторых, использовать htmlspecialchars для экранирования символов, полученных из GET запроса.
// index.php
$input = isset($_GET['name']) ? $_GET['name'] : 'World';
header('Content-Type: text/html; charset=utf-8');  
printf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8'));  
  • Этот участок кода - не тестируемый (даже с учетом того, что здесь практически нечего тестировать).

Все, кто считают, что безопасность и тестирование - еще не веский повод перестать писать код в старой манере, могут уходить и продолжать работать :)

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

Добавим слой отображения и подключим Bootstrap

Bootstrap - это популярный css фреймворк, который в разы ускорит вашу работу с отображением, особенно если макет приложения нужен быстро, а времени отвлекаться на верстку нет.

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

<!DOCTYPE html>  
<html lang="en">  
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Bootstrap 101 Template</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    </head>
    <body>
        <h1>Hello, world!</h1>
    </body>
</html>  

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

// index.php
<?php  
    $input = isset($_GET['name']) ? $_GET['name'] : 'World';
    $input = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
    header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>  
<html lang="en">  
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Bootstrap 101 Template</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    </head>
    <body>
        <h1>Hello, <?=$input?>!</h1>
    </body>
</html>  

Обратите внимание на строку #16, <?=$input?> - это краткий эквивалент  <?php echo $input; ?>.

Теперь, открыв 127.0.0.1:8999?name=Anna, вы увидите, что заголовок отображается с использованием подключенных стилей.

Инициализация git-репозитория

Открываем консоль, переходим в наш каталог с приложением и инициализируем git-репозиторий:

cd /your/work/place/feedlerapp  
git init  

Эта команда создает в текущем каталоге новый подкаталог с именем .git, содержащий все необходимые файлы репозитория — основу git-репозитория. Однако на этом этапе index.php еще не находится под версионным контролем. Выполняем команду:

git status 

Ее результатом будет отображение состояния текущего каталога:

$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   index.php
nothing added to commit but untracked files present (use "git add" to track)  

Мы видим, что файлы index.php не отслеживаются. Чтобы начать отслеживание (добавление под версионный контроль) новых файлов, используется команда git add. Начнем отслеживать файл index.php:

$ git add index.php

Если вы снова выполните команду status, то увидите, что теперь файл index.php - отслеживаемый и индексированный:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   index.php
#

На этой стадии мы готовы зафиксировать все произведенные изменения. Запомните, всё, что не было до сих пор проиндексировано — любые созданные или измененные вами файлы, для которых вы не выполнили  git add после редактирования — не войдут в этот коммит. Они останутся измененными файлами на вашем диске. В нашем случае, когда вы в последний раз выполняли git status, вы видели, что всё уже проиндексировано, и вот вы готовы к коммиту. Простейший способ зафиксировать изменения — набрать git commit:

$ git commit -am 'Init git repository and create simply app'

Результатом будет:

[master]: created 463dc4f: "Init git repository and create simply app"
files changed, 36 insertions(+), 0 deletions(-)  
create mode 100644 index.php  

Поздравляю, вы создали свой первый коммит! Вы можете видеть, что коммит вывел вам немного информации о себе: на какую ветку вы выполнили коммит (master), какая контрольная сумма SHA-1 у этого коммита (`463dc4f`), сколько файлов было изменено, а также статистику по добавленным/удаленным строкам в коммите.

На сегодня всё, продолжение - в следующей статье :)