Общий маршрут PHP: как работает front controller

Раздел: Маршрутизация в веб-приложениях -> Маршруты PHP

Маршрут общей страницы в 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)

Пояснение шагов:

  1. Извлекается путь из $_SERVER['REQUEST_URI'] с помощью parse_url для отсечения query-строки.
  2. Массив $routes хранит шаблоны и замыкания.
  3. Функция route проходит по всем маршрутам, заменяет {param} на группу захвата ([^/]+) и проверяет совпадение.
  4. При совпадении извлекаются параметры (кроме полного совпадения) и передаются в обработчик.
  5. Если ни один маршрут не подошёл, возвращается 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-route

Index 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/altorouter

Php 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 route product search (маршрут поиска товаров php)
- Index php route extension (маршрут расширения php)
- Route index php page (маршрут страницы php)

Расширенные примеры реализации маршрутизации через 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.

Маршрут общей страницы PHP - comments

En
Index php route common (php)