Общий маршрут PHP: как работает front controller
Маршрут общей страницы в PHP через index.php
Когда веб-приложение строится на PHP, часто применяется шаблон Front Controller - единая точка входа через файл index.php. Все HTTP-запросы направляются на этот файл, а внутри него происходит маршрутизация: определение, какой контроллер или обработчик должен отработать. Такой подход упрощает структуру проекта, централизует обработку ошибок, авторизацию и логирование.
Как реализовать единую точку входа с поддержкой параметров маршрута?
Самое эффективное и гибкое решение - написать собственный простой роутер на основе регулярных выражений. Он разбирает URI, извлекает параметры и вызывает нужную функцию или метод класса.
<?php
// index.php - точка входа
// Получаем путь из REQUEST_URI, удаляем GET-параметры
$uri = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri, PHP_URL_PATH);
// Определяем маршруты
$routes = [
'/' => function() { echo 'Главная'; },
'/about' => function() { echo 'О нас'; },
'/article/{id}' => function($id) { echo "Статья #$id"; },
'/user/{name}/{age}' => function($name, $age) { echo "Пользователь $name, возраст $age"; },
];
// Функция маршрутизации
function route($uri, $routes) {
foreach ($routes as $pattern => $handler) {
// Преобразуем шаблон {param} в регулярное выражение
$regex = preg_replace('/\{[a-zA-Z_]+\}/', '([^/]+)', $pattern);
$regex = '#^' . $regex . '$#';
if (preg_match($regex, $uri, $matches)) {
array_shift($matches); // удаляем полное совпадение
// Вызываем обработчик с параметрами
return call_user_func_array($handler, $matches);
}
}
// 404
http_response_code(404);
echo 'Страница не найдена';
}
route($uri, $routes);Route info php id (информация о маршруте по id php)
Пояснение шагов:
- Извлекается путь из $_SERVER['REQUEST_URI'] с помощью parse_url для отсечения query-строки.
- Массив $routes хранит шаблоны и замыкания.
- Функция route проходит по всем маршрутам, заменяет {param} на группу захвата ([^/]+) и проверяет совпадение.
- При совпадении извлекаются параметры (кроме полного совпадения) и передаются в обработчик.
- Если ни один маршрут не подошёл, возвращается 404.
Типичная ошибка: забыть экранировать слэши в регулярном выражении или не учитывать, что parse_url может вернуть false при некорректном URL. Рекомендуется всегда проверять результат parse_url.
Проблема производительности: при большом количестве маршрутов (сотни) проход по всему массиву на каждый запрос может быть медленным. В реальных проектах лучше использовать кеширование регулярных выражений или готовые библиотеки с трие-структурами.
Как сделать маршрутизацию без mod_rewrite (через параметр GET)?
Если сервер не поддерживает модуль rewrite, можно передавать имя маршрута через GET-параметр, например: index.php?route=about. Это простейший способ, но URL становятся некрасивыми.
<?php
$route = $_GET['route'] ?? 'home';
switch ($route) {
case 'home':
echo 'Главная';
break;
case 'about':
echo 'О нас';
break;
default:
http_response_code(404);
echo '404';
}Ru index php route (маршрут index.php с русским языком)
Ошибка: при неверном пути пользователь видит 404, но адресная строка остаётся прежней. Невозможно передать динамические параметры (например, id статьи) без дополнительной обработки.
Решение: добавить извлечение параметров через explode или регулярку, но это быстро усложняет код.
Как просто обработать несколько статических маршрутов (switch-case)?
Когда маршрутов мало и нет динамики, подойдёт конструкция switch по значению $_SERVER['REQUEST_URI'].
<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
switch ($uri) {
case '/':
include 'home.php';
break;
case '/about':
include 'about.php';
break;
default:
include '404.php';
}
Admin index php route (маршрут админки php)
Проблема: при добавлении нового маршрута нужно менять index.php. switch не поддерживает параметры в пути, поэтому для каждого нового шаблона придётся писать дополнительную логику.
Рекомендация: такой вариант годится только для самых маленьких проектов (до 5 статических страниц).
Как использовать готовую библиотеку для быстрой маршрутизации (FastRoute)?
Библиотека nikic/FastRoute - один из самых быстрых роутеров для PHP. Она использует оптимизированное регулярное выражение, которое строится один раз и затем применяется ко всем запросам.
composer require nikic/fast-routeIndex php route information (маршрут информационной страницы php)
<?php
require 'vendor/autoload.php';
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/', 'HomeController@index');
$r->addRoute('GET', '/about', 'AboutController@index');
$r->addRoute('GET', '/article/{id:\d+}', 'ArticleController@show');
});
// Получаем HTTP-метод и URI
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
http_response_code(404);
echo '404 Not Found';
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
http_response_code(405);
echo '405 Method Not Allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
echo call_user_func_array($handler, $vars);
break;
}Php route product category (маршрут категории товара php)
Цель использования: высокая производительность, поддержка placeholder'ов с валидацией (например, {id:\d+}), автоматический разбор HTTP-методов.
Типичная ошибка: неверное использование пространства имён или опечатки в именах классов. Также важно помнить, что simpleDispatcher принимает замыкание, которое выполняется один раз при запуске - не стоит помещать туда тяжёлые операции.
Как использовать простой роутер с поддержкой именованных маршрутов (AltoRouter)?
Библиотека altorouter/altorouter предоставляет удобный синтаксис и возможность генерировать URL по имени маршрута.
composer require altorouter/altorouterPhp route product category path (маршрут категории товара с путем php)
<?php
require 'vendor/autoload.php';
$router = new AltoRouter();
$router->setBasePath('/myapp'); // если приложение в поддиректории
// Определяем маршруты
$router->map('GET', '/', 'home', 'HomeController#index');
$router->map('GET', '/about', 'about', 'AboutController#index');
$router->map('GET', '/article/[i:id]', 'article_show', 'ArticleController#show');
// Сопоставляем текущий URI
$match = $router->match();
if ($match) {
$target = $match['target']; // строка вида 'Controller#method'
$params = $match['params'];
// Можно разобрать target и вызвать нужный метод
list($controller, $action) = explode('#', $target);
$controller = new $controller();
echo call_user_func_array([$controller, $action], $params);
} else {
http_response_code(404);
echo '404';
}Пояснение:
- setBasePath - если приложение находится не в корне домена.
- Плейсхолдеры: [i:id] - только цифры, [*:slug] - любая строка, [a:name] - буквы.
- Именованные маршруты (третий аргумент) позволяют генерировать URL: $router->generate('article_show', ['id' => 42]).
Ошибка: при использовании setBasePath нужно указывать полный путь без завершающего слэша, иначе сопоставление может работать некорректно.
Проблема: AltoRouter не поддерживает автоматическое кеширование регулярных выражений, поэтому при большом количестве маршрутов может быть медленнее FastRoute.
Расширенные примеры реализации маршрутизации через index.php
Пример 1: Маршруты с группировкой и middleware (на основе самописного роутера)
Добавим поддержку групп маршрутов (префиксов) и middleware - функций, выполняемых перед обработчиком. Это удобно для проверки авторизации или логирования.
<?php
// index.php - улучшенный роутер
class Router {
private $routes = [];
private $before = []; // глобальные middleware
public function add($method, $pattern, $handler, $middleware = null) {
$this->routes[] = compact('method', 'pattern', 'handler', 'middleware');
}
public function group($prefix, $callback) {
// Сохраняем текущий префикс, вызываем callback, восстанавливаем
// Упрощённо: передаём префикс через контекст
$callback($this, $prefix);
}
public function run() {
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
foreach ($this->routes as $route) {
// Поддержка префикса: сразу добавим его в шаблон
$regex = preg_replace('/\{[a-zA-Z_]+\}/', '([^/]+)', $route['pattern']);
$regex = '#^' . $regex . '$#';
if (preg_match($regex, $uri, $matches) && $route['method'] === $method) {
array_shift($matches);
// Выполняем middleware, если есть
if ($route['middleware']) {
$result = call_user_func($route['middleware'], $uri, $matches);
if ($result === false) {
http_response_code(403);
echo 'Доступ запрещён';
return;
}
}
// Выполняем обработчик
call_user_func_array($route['handler'], $matches);
return;
}
}
http_response_code(404);
echo 'Не найдено';
}
}
// Использование
$router = new Router();
// Глобальный middleware для логирования
$loggerMiddleware = function($uri, $params) {
error_log("Запрос: $uri");
return true;
};
// Можно добавить глобальные фильтры (не показаны)
// Определяем маршруты
$router->add('GET', '/', function() { echo 'Главная'; }, $loggerMiddleware);
$router->add('GET', '/about', function() { echo 'О нас'; });
// Группа /admin с middleware авторизации
$authMiddleware = function($uri, $params) {
if (!isset($_SESSION['user'])) {
header('Location: /login');
return false;
}
return true;
};
$router->add('GET', '/admin', function() { echo 'Админка'; }, $authMiddleware);
$router->add('GET', '/admin/users', function() { echo 'Список пользователей'; }, $authMiddleware);
$router->run();// Результат при посещении /admin без сессии: редирект на /login
Пример 2: Использование регулярных выражений с именованными группами
Самописный роутер можно улучшить, применяя именованные группы захвата в регулярных выражениях. Это позволяет передавать параметры по имени.
<?php
$uri = '/user/john/25/';
$patterns = [
'/user/{name}/{age}/' => 'user_handler',
];
foreach ($patterns as $pattern => $handler) {
// Преобразуем {name} в (?P<name>[^/]+)
$regex = preg_replace('/\{([a-zA-Z_]+)\}/', '(?P<$1>[^/]+)', $pattern);
$regex = '#^' . $regex . '$#';
if (preg_match($regex, $uri, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY); // только именованные
// $params = ['name' => 'john', 'age' => '25']
call_user_func($handler, $params);
}
}// Параметры передаются ассоциативным массивом
Пример 3: Маршрутизация с поддержком различных HTTP-методов (POST, PUT, DELETE)
В реальном приложении важно учитывать не только URI, но и HTTP-метод. Пример на основе FastRoute (который поддерживает это из коробки).
<?php
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/user/{id:\d+}', 'getUser');
$r->addRoute('POST', '/user', 'createUser');
$r->addRoute('PUT', '/user/{id:\d+}', 'updateUser');
$r->addRoute('DELETE', '/user/{id:\d+}', 'deleteUser');
});
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
if ($routeInfo[0] === FastRoute\Dispatcher::FOUND) {
$handler = $routeInfo[1];
$vars = $routeInfo[2];
echo "Обработчик: $handler, параметры: " . json_encode($vars);
} else {
http_response_code(404);
echo 'Not Found';
}// При GET /user/123 - выведет: Обработчик: getUser, параметры: ["id":"123"] // При POST /user - Обработчик: createUser, параметры: []
Пример 4: Генерация URL по имени маршрута в AltoRouter
Функция generate упрощает создание ссылок, особенно при изменении путей.
<?php
$router = new AltoRouter();
$router->map('GET', '/product/[i:id]/[a:slug]', 'product_show', 'ProductController#show');
// Генерация URL:
$url = $router->generate('product_show', ['id' => 10, 'slug' => 'laptop']);
// Результат: /product/10/laptop
echo $url;/product/10/laptop
Пример 5: Обработка ошибок 404 с сохранением пути
Иногда нужно перенаправить пользователя на специальную страницу 404, но при этом запомнить, какой путь был запрошен.
<?php
// В самописном роутере после цикла, если маршрут не найден:
$requestedPath = $_SERVER['REQUEST_URI'];
http_response_code(404);
include '404.php'; // в 404.php можно вывести $requestedPath// Пользователь увидит: "Страница /wrong-path не найдена"
Эти примеры охватывают большинство сценариев использования маршрутизации через index.php: от простых статических путей до продвинутой группировки и генерации URL.