Mvc php framework своими руками

Простой, современный MVC фреймворк на PHP для разработки сайтов «с нуля»

Цель данной статьи — поделиться опытом по написанию простого ООП MVC PHP фреймворка. Так же хочу предоставить сообществу исходный код и попросить критики, одобрения, замечаний и поддержки.

Введение

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

Как показала дальше практика: читать, знать, слышать о чем-либо, и уметь самому это реализовать — совершенно разные вещи. Теоретизировать можно бесконечно, но только настоящее практическое задание позволяет понять, на каком уровне ты находишься. Всвязи с этим и было начато «написание собственного велосипеда». Каким он получился — судить вам.

Процесс разработки

Разработка фреймворка велась следующим образом: изначально было некое простейшее веб-приложение, которое дорабатывалось, переписывалось, меняло структуру, обрастало новыми классами и компонентами и т. д. Несколько месяцев назад у меня появилось свободное время, много энтузиазма и решительности таки доделать фреймворк «по-серьезному». На написание данной версии я потратил в совокупности 3-4 недели (работая в среднем 1-3 часа в день, 3-4 дня в неделю).

По мере разработки стандарты и требования я сознательно завышал для себя, искал оптимальные решения много раз переписывал код. Так, например, работу с конфигурацией я переделывал раз 5-6 (причем несколько раз кардинально), роутинг — 3-4 раза. В качестве примеров я брал код из статей, публикаций, руководств, фреймворков (Yii2, CodeIgniter, Zend, Phalcon, Bun) и т. п.

Читайте также:  Php and cgi bin

Анализ требований

Все начинается с анализа требований и пожеланий к итоговой системе.

  • позволять быстро создать сайт «с нуля»
  • иметь в себе ряд уже реализованных базовых технических решений и инструментов
  • содержать разделенный frontend и backend
  • отвечать современным требования по коду, технологиям, применяемым техническим решениям и т.п.
  • содержать уже в базовой комплектации демо-приложение, на основе которого можно вести свою разработку
  • быть модульным и расширяемым
  • иметь понятную документацию, техподдержку (в идеале — сообщество)

Применяемые технологии

Список таких решений напрямую зависит от того, о чём знаете и что применяете в своей реальной практике. Т.е. подходим к необходимости постоянного мониторинга новинок и изменений в сфере ИТ.

Практики и технологии:

  • Язык программирования: PHP >= 5.5.* или PHP >= 7.*
  • База данных: MySql >=5.4.*
  • Менеджер пакетов: Composer
  • Автозагрузка: PSR-4, кодирование: PSR-2, логирование: PSR-3
  • Используем функционал языка: неймспейсы, трейты, магические функции и т.п.
  • Применяем паттерны при построении структуры классов, реализации задач
  • Верстаем html-код с использованием Twitter Bootstrap
  • Пользуемся лучшими подходами в программировании: SOLID, DRY, KISS, YAGNI
  • Покрываем код PhpUnit-тестами (тестирование работы базовых классов приложения)
  • покрываем функционал Codeception-тестами (приемочное тестирование)

Структура папок

Приведу структуру файлов и папок в фреймворке (также можно посмотреть код на GitHub):

image

Код

В приложении есть одна единственная точка входа. Привожу код файла index.php из корневой публичной папки веб-сервера.

session_start(); $loader = require(__DIR__ . '/../../vendor/autoload.php'); $loader->addPsr4('framework\\', __DIR__ . '/../../system/'); $loader->addPsr4('frontend\\', __DIR__ . '/../'); $loader->addPsr4('common\\', __DIR__ . '/../../common/'); $config = array_merge( require(__DIR__ . '/../config/main.php'), require(__DIR__ . '/../../common/config/main.php') ); $appication = new \framework\core\Application(); $appication->run($config); 

Код метода run($config) из класса \framework\core\Application(). Производится загрузка необходимых классов приложения и производится вызов соответствующего контроллера (в методе execute()).

 /** * * @param array $config */ public function run($config = []) < $this->benchmark = new Benchmark(); $this->environment = Environment::get(); $this->config = new Registry($config); $this->response = new Response(); $this->request = Request::getInstance(); $this->assets = new Asset($this->config->assets); $this->setParams(); $this->router = new Router($this->config->routes); $this->execute(); > 

Код метода execute() из класса \framework\core\Application(). Нужный контроллер на данном этапе уже выбран, производим инициализацию этого контроллера, обработку хеадеров, вывод контента. В случае ошибки — бросаем 404 Not Found.

 public function execute() < $controllerName = $this->router->getControllerName(); try < $controllerClass = '\\' . $this->config->name . '\controllers\\' . $controllerName . 'Controller'; if (class_exists($controllerClass)) < $controller = new $controllerClass; if ($controller instanceof Controller) < $controller->setApplication($this)->run(); > > else < throw new CoreException('Controller "' . $controllerName . '" not exists: ' . Request::getInstance()->server["REQUEST_URI"]); > > catch (CoreException $e) < $e->logError(); $this->response->setHeader("HTTP/1.1 404 Not Found"); $this->router->error404(); $this->execute(); exit(); > foreach ($this->response->getHeaders() as $header) < header($header); >echo $this->response->getContent(); > 

Улучшения и планы на будущее

В качестве адаптера для коннекта к БД я использовал PDO. В ходе работы PDO мне не очень понравился — сложно отлаживать запросы, хочется комфорта использования ORM. Можно установить Eloquent ORM — это современное и готовое решение (применяется в фреймворке Laravel), да и к тому же оно хорошо документировано и может быть установлено из composer за несколько минут.

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

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

Заключение

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

Так же хотелось бы реализовать какой-либо проект на базе данного фреймворка. Так сказать опробовать инструмент в работе. Понятно, что поиск заказчиков — это совсем не к данному разделу, но хотел бы услышать, можно ли на данном решении стартовать реальный проект? Популярные фреймворки «из коробки» дают функционал в 50-100 раз качественнее и масштабнее, конкурировать с ними сложно.

Источник

Разработка своего MVC фреймворка на PHP

В предыдущих уроках вы тренировались использовать готовый MVC фреймворк. Как правило, этим PHP программисты и занимаются — берут один из популярных готовых фреймворков, изучают его, а потом используют. В настоящее время есть 3 самых популярных фреймворка: Laravel, Yii и Symfony.

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

Далее в данном учебнике мы с вами разработаем свой MVC фреймворк на PHP. Еще раз подчеркну, что данный этап уже не обязателен, но поспособствует закреплению ваших знаний ООП на практическом примере.

Итак, приступим к разработке. На самом деле вы будете разрабатывать не какой-то абстрактный фреймворк, а просто реализуете функционал того учебного фреймворка, который мы использовали в предыдущих уроках.

Вы уже знаете, какой функционал у вас должен быть. Осталось его реализовать. Приступим!

Точка входа

Для начала в корневой папке вашего домена сделаем файл index.php со следующим содержанием:

Создайте файл index.php и добавьте в него указанные строки.

Настраиваем htaccess

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

Вот содержимое файла htaccess :

Вспомним теперь, что адреса из папки project/webroot не должны перенаправляться на индекс, так как там мы храним стили, скрипты, картинки и тому подобные вещи. Учтем это в нашем htaccess :

Создайте файл htaccess . Выполните описанную настройку. Проверьте ее работу: все адреса, кроме адресов из папки project/webroot должны редиректится на index .

Автозагрузка классов

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

Реализуйте функцию автозагрузки. Проверьте ее работу.

Источник

Пишем мини MVC фреймворк на PHP #1

Привет, хабр! В этой статье я хочу написать о том, как сделать PHP-приложение с помощью схемы разделения данных приложения MVC.

Для работы нам нужна функция под названием autoload. Она избавляет нас от бесконечных require’ов. Мы можем вручную написать скрипт, но эта функция есть у знаменитого пакетного менеджера composer.

После установки инициализируем его в главной папке нашего мини-фреймворка командой composer init. на всех вопросах нажимаем ENTER.

Далее заходим в появившийся файл composer.json. Удаляем все и добавляем это:

И наконец, выполняем команду composer update. На этом настройка composer завершена.

Теперь, создадим папку core и файл .htaccess. Еще нужно создать папку public и создать в ней файл index.php — точку входа в приложение.

В файл .htaccess нужно вписать следующее:

RewriteEngine on RewriteRule .* public/index.php

Все, что делает этот файл — переадресовывает любые запросы в index.php.

Потом, в папке core создаем класс Application. Помещаем в него этот код:

Здесь мы создаем пока что пустой класс и пространством имен app\core.

На этом этапе структура должна выглядеть так:

│ .htaccess
│ composer.json
│ composer.lock

├───core
│ Application.php

├───public
│ index.php

└───vendor

Отлично. Теперь давайте выполним первую задачу: маршрутизацию.

Маршрутизация

В папке core создаем класс Router.php и начнем писать код:

routes['get'][$path] = $callback; > public function post($path, $callback) < $this->routes['post'][$path] = $callback; > >

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

Теперь нужно создать класс Request.php для получения урлов, методов запроса и так далее:

 public function getMethod() < return strtolower($_SERVER['REQUEST_METHOD']); >>

Тут все просто: метод getPath служит для получения url без GET-параметров, а getMethod просто возвращает HTTP-метод. Модифицируем класс Роутера:

request = new Request(); > public function get($path, $callback) < $this->routes['get'][$path] = $callback; > public function post($path, $callback) < $this->routes['post'][$path] = $callback; > public function resolve() < $path = $this->request->getPath(); $method = $this->request->getMethod(); $callback = $this->routes[$method][$path] ?? false; if ($callback === false) < return "404"; >return call_user_func($callback); > >

Тут мы создаем экземпляр Request’а и метод resolve, который возвращает то, что вернул callback.

Возвратимся в класс Application и создаем метод run, который запустит Роутер:

router = new Router(); > public function run() < echo $this->router->resolve(); > >

Теперь, можем протестировать текущий функционал. Создадим папку public и в ней файл index.php:

router->get('/', function () < return "Hello, habr!"; >); $app->run();

В этой же папке запустим команду php -S localhost:8080 (или любой другой порт). Зайдем на localhost:8080 в браузере и о чудо! Мы увидим надпись Hello, habr!

Итоги

На этом первая часть подходит к концу. В ней мы задали каркас нашего будущего фреймворка. В следующей части мы реализуем View и Контроллеры

Это моя первая статья на Хабре, поэтому буду рад любой критике. Спасибо за прочтение и удачи!

Источник

Оцените статью