Реализовываем простенький mvc-фреймворк (Часть 1)
Думаю, не стоит говорить, что каждый php-разработчик (без разницы с каким опытом) писал (пишет?) велосипеды фреймворки штучку под названием mvc.
Уверен, что многие все же смогли это сделать и теперь они довольны. Если это не про Вас — можно читать дальше.
В данном цикле постов я хотел бы поделиться с Вами своим опытом по созданию такого велосипеда.
За идею я взял laravel (если точнее — методы, классы, названия и другое) и попытался сделать что-то подобное.
P.s: наш mvc проект уже готов, поэтому вы будете встречать названия классов, методов которых еще не создавали. Все будет создано в дальнейшем. Не переживайте.
В комментариях к методу может быть @throws ModuleName — Не обращайте внимание, мы будем использовать \Exception
Приступим
Рассказывать Вам теорию я не особо хочу, любой, кому это интересно, может прочесть википедию, так что, приступаем.
Начальная архитектура:
создаем папки: app — папка нашего приложения, тут будут лежать контроллеры, модели и т.п, core — «сердце» нашего фреймворка (его система), public — точка входа.
Папки создали, теперь нужно инициализировать composer.
Открываем консоль/терминал, заходим в папку с проектом и пишем composer init.
Package name (я привык использовать свой логин и название репозитория на гитхабе): login/repository-name;
Description: enter;
Author: n,
Minimum Stability: dev
Package Type: project
License: enter,
Would you like to define...: n
Do you confirm generation: enter
Итак, у нас должен был появится файлик composer json, заходим в него и ниже «require»: {} пишем следующее:
"autoload": { "psr-4": { "app\\": "app/", "core\\": "core/" } }Теперь нужно запустить команду composer update. У нас появится папка vendor.
Отлично. Теперь мы можем приступать к написанию нашего приложения :)
Ну что же, наш сервис контейнер будем таким:
public static function getInstance(): ServiceContainer; // Реализация синглтона public function set(string $key, $object): void; // Метод для добавления нового класса public function createAlias(string $key, string $alias): mixed; // Реализация class_alias php public function onlyLoadClass(array $classes): void; // Будем использовать в дальнейшем public function bildClass(string $key, $params = null): object; // Возвращаем объект класса по названию private function instance($key, $parameters = null): object; // Занимается созданием объектов
А вот так наш класс будет выглядеть с реализованными методами:
просмотр
Отлично, сервис контейнер готов. Теперь идем в папку public и создаем там файл index.php с таким содержанием:
require '../vendor/autoload.php'; (new \core\Application)->run();Затем: гугл -> .htaccess index.php -> копируем -> вставляем в public/.htaccess. Для тех кто не понял: создаем .htaccess в public и суем туда правила редиректа на index.php (входная точка).
Займемся главным файлом нашего приложения (запуск нашего приложения).
Предлагаю вам такую версию:
public function run(): void; private function loadAliases(): void; // Будем использовать в дальнейшемРеализация класса
И тут у нас появляется множество не понятных методов и классов. Надеюсь, вы прочли " p.s «?
Теперь создаем папочку ’config’ в главной директории нашего приложения. Создаем файл app.php и пишем следующее:
<?php return [ // Классы которые будут загружены при запуске приложения 'required' => [ \core\collection\Collection::class, ], // Алиасы для классов 'aliases' => [ ] ];В дальнейшем у нас тут появится еще множество других настроек, но сейчас будет достаточно этого. Для тех кто не понял — ’required’ и ’aliases’ используются сервис контейнером при запуске. Аналогичная логика и у Laravel.
Время для функций :)
Создаем папку helpers в core и создаем файл functions.php
Идем в composer.json и ниже «psr-4» пихаем:
"files": [ "core/helpers/functions.php" ]
А вот и само содержание файла functions.php
<?php function app() { return \core\container\ServiceContainer::getInstance(); } function config() { return app() ->set('config', '\core\config\Repository') ->bildClass('config'); } function route() { return app()->bildClass('Route'); } function collect(array $data = []) { return app()->bildClass('Collection', $data); }Догадались что это? Да, правильно. Это аналогия app(), config(), route() и т.п в Laravel’e.
Теперь многое выше стало проясняться, не так ли?
Сейчас создадим один файлик и опишем его, для чего он — сами поймете, он потребуется нам в дальнейшем.
core\collection\Collection.php
Реализация класса
Этот файл мы обсудим позже, сейчас просто скопируйте его.
Ну что же, самое время для системы роутеров.
Начнем с файлов
core\routers\BaseRoute.php;
protected static $routers = []; // Все роутеры protected static $patterns = [ '{integer}' => '[0-9]+', '{string}' => '[a-zA-Z]+', '{any}' => '[^/]+', ]; public static function get(...$arguments): void; public static function post(...$arguments): void; private static function addRouter(string $method, $arguments): void; public function startRoute(); private function initRout($matches); private function initNotFoundRout();
core\routers\Router.php;
core\traits\Router\ParseUrl.php
public static function parse(string $key): array; public static function replaceUrl(string $key);
core\traits\Router\RouteHelper.php
public function returnCurrentUrl($uri = false): string; public function removeSlashes(string $uri, $currentUrl): string; private function replacePreg($uri);
Возвращаемся в config/app.php и в aliases пишем:
'Route' => \core\routers\Router::class,
Ну что же, теперь самое время тестировать нашу систему роутеров.
Создаем папку routers в app и создаем файл main.php (app\routers\main.php)
Проверяем работу:
Route::get('/', function() { echo 'Главная страница'; });
Можете поиграться
Route::get('/{string}/name{integer}-{any}');
На этом все. В дальнейшем займемся остальными компонентами системы.
14 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів