Будуємо свій PHP фреймворк на компонентах Symfony

Вам, як PHP-розробнику, швидше за все, доводилося мати справу з Symfony. Ну принаймні ви про нього чули. Чого ви, можливо, не знаєте - так це те, що Symfony у своїй основі складається з набору роздільних бібліотек, які називають компонентами, які можна використовувати окремо в будь-якому PHP додатку.

Наприклад, популярний фреймворк Laravel був розроблений з використанням кількох компонентів Symfony. У нашому уроці ми також їх використовуватимемо. Наступна версія популярної CMS Drupal також побудована на деяких основних компонентах Symfony.

Тут ми розглянемо, як побудувати невеликий PHP фреймворк з використанням цих компонентів, і як вони можуть взаємодіяти для створення базової структури будь-якої веб-програми.

symfony

Зауважу, що в цій статті я не розглядатиму кожен компонент Symfony та їх можливості. Я розповім тільки про основні речі, які потрібні для того, щоб побудувати фреймворк, що мінімально функціонує. Якщо ви хочете ближче познайомитися з компонентами Symfony, я рекомендую вам звернутися до документації.

Створюємо проект

Почнемо з нуля, з простого файлу index.php у корені проекту, а для встановлення залежностей будемо використовувати Composer.

На даному етапі наш файл міститиме простий фрагмент коду:

Цей код просто зіставляє запитаний URL фрагмент (який міститься в $_SERVER['PATH_INFO'] ) відповідної інструкції echo . Це дуже простий маршрутизатор.

Компонент HttpFoundation

HttpFoundation грає роль високорівневої абстракції до роботи з HTTP потоком. Найважливішими його точками входу є класи Request та Response.

Request дає можливість працювати з інформацією HTTP запиту, такий як запит URI або заголовки клієнта,є надбудовою над суперглобальними масивами PHP ( $_GET , $_POST і т.д.). Response використовується для відправки HTTP заголовків і даних клієнту, замість того, щоб користуватися стандартними header і echo, як це було б у "класичному" PHP.

Встановимо за допомогою composer:

Ця команда помістить компонент а директорію vendor. Тепер вставте цей код у файл index.php:

Те, що ми тут зробили, не є чимось особливим:

  • Створюємо екземпляр Request за допомогою статичного методу createFromGlobals. Замість створення порожнього об'єкта, він заповнює об'єкт Request даними поточного запиту;
  • Перевіряємо значення, отримане за допомогою методу getPathInfo.

Також ми можемо замінити конструкції echo на використання об'єкта Response для зберігання вихідних даних, і скористатися методом send для надсилання відповіді клієнту (що насправді виводить у буфер виведення заголовки та вміст).

Використовуємо HttpKernel як обгортку над ядром фреймворку

На даний момент у нас найпростіший випадок – вся логіка фреймворку розташована у нашому фронт-контролері – файлі index.php. Якщо ми хочемо додати ще код, то краще відокремити його в інший клас, який стане "ядром" нашого фреймворку.

Компонент HttpKernel якраз і замислювався для цього. Він розрахований на роботу з HttpFoundation, об'єкт Request конвертується в об'єкт Response, а також надає кілька класів для досягнення цієї мети. Зараз ми будемо використовувати HttpKernelInterface. Цей інтерфейс визначає лише один метод: handle.

Цей метод приймає як аргумент об'єкт Request, і передбачає повернення об'єкта Response. Отже, будь-який клас, що реалізує цей інтерфейс, може обробити запит.Request, і повернути відповідь Response.

Давайте створимо клас Core нашого фреймворку, який реалізує інтерфейс HttpKernelInterface. Створіть файл Core.php у директорії lib/Framework.

Зауваження : метод handle також приймає два опціональні аргументи: тип запиту, і булев аргумент, що вказує, чи має ядро ​​викидати виняток у разі помилки. У цій статті ми їх використовувати не будемо, але ми повинні реалізувати метод точно в такій формі, як він описаний в інтерфейсі HttpKernelInterface , інакше PHP викине помилку.

Єдине, що ми зробили в цьому фрагменті – перенесли код у метод handle. Тепер ми можемо позбавитися цього коду у файлі index.php , і замість нього використовувати свіжостворений клас:

Поліпшена система маршрутизації

У нашому класі все ще є проблема: він все ще опрацьовує маршрутизацію по всьому додатку. При необхідності додавання нових URL нам доведеться змінювати код усередині фреймворку, що безумовно не є гарною ідеєю. Більше того, це вимагатиме додавання нових блоків case для кожного нового маршруту. Ні, ми напевно не хочемо йти цією слизькою доріжкою.

Рішенням буде додавання у фреймворк системи маршрутизації. Зробити це можна, створивши метод map, який зіставляє URI із замиканням PHP, яке буде виконано у випадку, якщо URI відповідає маршруту.

Тепер маршрути можна додавати прямо у фронт-контролері:

Нам потрібна гнучкіша і потужніша система маршрутизації, ось чому нам слід використовувати компонент Routing.

Використання компонента Routing дозволить нам передавати об'єкти Route (маршрути) в UrlMatcher , який зіставить запит URI відповідному маршруту. Цей об'єкт Route може містити будь-які атрибути, які допоможутьнам виконати необхідну частину програми. У нашому випадку такий об'єкт міститиме замикання, яке має бути виконане у разі збігу маршруту. Також, будь-який динамічний параметр, що міститься в URL, буде присутній у списку атрибутів маршруту.

Для того щоб реалізувати цю систему, нам потрібно зробити такі зміни:

  • замінити масив routes екземпляром RouteCollection для зберігання наших маршрутів;
  • поміняти логіку методу map так, щоб він реєстрував екземпляр Route у цій колекції;
  • створити об'єкт UrlMatcher та вказати йому, як шукати відповідності маршрутів у переданому URI, вказавши відповідний контекст за допомогою об'єкта RequestContext .

Метод match спробує знайти відповідний маршрут за переданим URL, і у разі успіху поверне відповідні атрибути маршруту. Інакше викине виняток ResourceNotFoundException , який ми можемо відловити та відобразити 404 сторінку.

Тепер можна скористатися компонентом маршрутизації для обробки будь-яких параметрів. Після позбавлення атрибута controller можна викликати будь-яке замикання, передавши йому параметри як аргументи (за допомогою функції call_user_func_array ):

Тепер ми з легкістю можемо обробляти динамічні URL-адреси:

Зверніть увагу, що тут ми робимо щось дуже схоже на те, що робить сам фреймфорк Symfony: ми впроваджуємо параметри URL у потрібний нам контролер.

Втручаємось у процес роботи фреймворку

Фреймворк Symfony також надає низку можливостей щодо впровадження у життєвий цикл запиту та його зміни. Хорошим прикладом є безпековий шар, що перехоплює запит, який намагається отримати доступ до захищеного URL.

Все це можливо завдяки компоненту EventDispatcher, що дозволяєрізним компонентам програми спілкуватися один з одним, реалізуючи шаблон проектування Спостерігач.

У серці цього компонента лежить клас EventDispatcher, який підписує передплатників окремі події. Коли диспетчера сповіщено про подію, викликаються всі відомі йому передплатники на цю подію. Передплатником може бути будь-яка функція зворотного виклику або метод.

Реалізувати в себе таку поведінку ми можемо, додавши властивість dispatcher , в якому зберігатиметься об'єкт EventDispatcher , а також метод on , який прив'язуватиме подію до функції зворотного виклику PHP. Диспетчер ми будемо використовувати для реєстрації функції зворотного дзвінка, і для подальшої генерації подій у фреймворку.

Тепер ми маємо можливість реєстрації передплатників, які є простими функціями зворотного виклику. Тепер давайте напишемо метод fire , який повідомить диспетчера про те, що треба сповістити всіх відомих передплатників про те, що сталася якась подія.

Менш ніж у десяти рядках коду ми додали хорошу систему обробки події до нашого фреймворку, і все це завдяки компоненту EventDispatcher.

Метод dispatch також приймає другий аргумент – об'єкт події. Кожна подія успадковується від загального класу Event і призначена для зберігання будь-якої пов'язаної з подією інформації.

Давайте напишемо клас події RequestEvent, яка буде негайно викликана, як тільки фреймворк опрацює запит. Звичайно, ця подія повинна мати доступ до поточного запиту за допомогою атрибуту, в якому зберігатиметься поточний екземпляр Request .

Тепер можна дописати код у методі handle таким чином, щоб він генерував подію RequestEvent щоразу, як ми отримали запит.

Таким чином, усі передплатники на цеподія матимуть доступ до об'єкта RequestEvent, а також до поточного екземпляра Request. На даний момент ми не написали такого передплатника, але можна легко уявити обробник, який до виконання основного коду перевірятиме, якщо до запитаного URL обмежений доступ.

Це найпростіша система безпеки, але ви можете реалізувати все, що вам буде завгодно, тому що тепер ви маєте можливість втручатися в процес роботи фреймворку в будь-який момент часу, що сильно розширює його можливості.

Висновок

З цієї статті можна побачити, що компоненти Symfony є чудовими самодостатніми бібліотеками. Більше того, вони можуть взаємодіяти один з одним для того, щоб утворювати фреймворк, який задовольняє вашим потребам. Є ще безліч компонентів, які, поза всякими сумнівами, дуже цікаві - наприклад, компоненти DependencyInjection або Security.

Зрозуміло, повнорозмірні фреймворки, як Symfony або Laravel використовували ці компоненти у всій повноті їхніх можливостей для того, щоб створити потужні інструменти, якими ми сьогодні володіємо.

Даний урок підготовлений для вас командою сайту ruseller.com Джерело уроку: http://www.sitepoint.com/build-php-framework-symfony-components/ Переклав: Станіслав Протасевич Урок створений: 23 Жовтня 2014 Переглядів: 15727 Правила передруку

5 останніх уроків рубрики "PHP"

Фільтрування даних за допомогою zend-filter

Коли йдеться про безпеку веб-сайту, фраза "фільтруйте все, екрануйте все" завжди буде актуальною. Сьогодні поговоримо про фільтрацію даних.

Контекстне екранування за допомогою zend-escaper

Підключення Zend модулів до Expressive

Expressive 2 підтримує можливість підключення інших компонентів ZF за спеціальною схемою. Не всім подобається це рішення. У цій статті ми розповімо, як покращили процес підключення кількох модулів.

Порада: надсилання інформації в Google Analytics через API

Припустимо, що вам необхідно надіслати якусь інформацію до Google Analytics із серверного скрипту. Як це зробити. Відповідь у цій нотатці.

Підбірка PHP пісочниць

Добірка з кількох видів PHP пісочниць. На деяких ви в режимі online зможете потішити свій код, але є рішення, які можна впровадити на свій сайт.