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

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

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

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

Будуємо свій 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 використовували ці компоненти в усій повноті їх можливостей, для того, щоб створити потужні інструменти, якими ми сьогодні володіємо.

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

За рахунок отримання інформації відразу по двох каналах (зір і слух) ефективність навчання значно перевершує навчання по книгах. А домашні завдання і онлайн-тести дозволять вам постійно думати на мові, що вивчається і відразу перевіряти свої знання!

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

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

Якщо ви давно хочете як слід вивчити HTML, то у мене для Вас є чудова новина!

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

Якщо ви вже вивчили HTML і хочете рухатися далі, то наступним кроком буде вивчення технології CSS.

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

Якщо ви хочете розібратися з поняттями домену і хостингу, навчитися створювати бази даних, закачувати файли сайту на сервер по FTP, створювати піддомени, налаштовувати поштові скриньки для свого сайту і стежити за його відвідуваністю, то цей курс створений спеціально для вас!