Построение маршрутизации для товаров: от простого парсинга до FastRoute

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

Разработка маршрутизации для страниц товара с использованием полного пути через index.php является одной из ключевых задач при построении веб-приложений. Правильная реализация позволяет создавать чистые URL, упрощает поддержку кода и улучшает SEO. В данной статье рассматриваются различные подходы к организации маршрута типа /product/123 или /product/some-slug с помощью PHP и центрального точки входа.

Основные варианты реализации маршрута товара

Как организовать маршрутизацию товаров с минимальным объемом кода и высокой производительностью?

Наиболее эффективным решением является использование готовой библиотеки FastRoute (разработчик Nikita Popov). Она обеспечивает быстрый разбор URL, поддержку параметров и кеширование маршрутов. Пример реализации:

// index.php - точка входа
require_once 'vendor/autoload.php';

use FastRoute\RouteCollector;

$dispatcher = FastRoute\simpleDispatcher(function(RouteCollector $r) {
    $r->addRoute('GET', '/product/{id:\d+}', 'ProductController::show');
    $r->addRoute('GET', '/product/{slug:[a-z0-9-]+}', 'ProductController::showBySlug');
});

$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);

switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        // вызов контроллера с параметрами
        list($class, $method) = explode('::', $handler);
        (new $class)->$method($vars);
        break;
    case FastRoute\Dispatcher::NOT_FOUND:
        http_response_code(404);
        echo 'Товар не найден';
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        http_response_code(405);
        echo 'Метод не разрешен';
        break;
}

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

  1. Подключается автозагрузка Composer.
  2. Создается диспетчер маршрутов с указанием правил. Используются именованные параметры с регулярными выражениями (например, \d+ для цифр).
  3. Извлекаются метод и URI из суперглобальных массивов.
  4. Метод dispatch возвращает статус и данные маршрута.
  5. В зависимости от статуса вызывается соответствующий обработчик или возвращается ошибка.

Распространенные проблемы:

  • Некорректная работа .htaccess – без перенаправления всех запросов на index.php маршруты не будут обрабатываться. Решение: добавить в корневой .htaccess строки RewriteEngine On и RewriteCond %{REQUEST_FILENAME} !-f с RewriteRule ^(.*)$ index.php [QSA,L].
  • Порядок маршрутов – если указать общий маршрут перед конкретным, он перекроет другие. Решение: размещать более специфичные маршруты раньше.
  • Кеширование маршрутов – при отсутствии кеша производительность снижается. FastRoute поддерживает кеширование через передачу файла кеша в simpleDispatcher().

Как реализовать маршрут товара без внешних библиотек, используя только нативный PHP?

Можно использовать простой парсинг URI с помощью explode и условных конструкций. Этот вариант полезен для небольших проектов или обучения.

// index.php без библиотек
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$segments = explode('/', trim($uri, '/'));

if ($segments[0] === 'product' && isset($segments[1])) {
    $productParam = $segments[1];
    if (is_numeric($productParam)) {
        // загрузка товара по ID
        $product = getProductById((int)$productParam);
    } else {
        // загрузка товара по slug
        $product = getProductBySlug($productParam);
    }
    if (!$product) {
        http_response_code(404);
        echo 'Товар не найден';
    } else {
        // отображение товара
        renderProduct($product);
    }
} else {
    // обработка других страниц
}

Как добавить поддержку нескольких языков или префиксов в URL товара?

Для этого можно использовать группировку маршрутов или параметры. В FastRoute это делается через вложенные маршруты или приставку /{lang:[a-z]{2}} перед путем. Пример с префиксом:

$r->addRoute('GET', '/{lang:en|ru}/product/{id:\d+}', 'ProductController::showLang');

Расширенные примеры и результаты их работы

Как обработать маршрут товара с числовым идентификатором и текстовым слагом одновременно?

Пример
// Использование FastRoute с двумя маршрутами и контроллером
$dispatcher = FastRoute\simpleDispatcher(function(RouteCollector $r) {
    $r->addRoute('GET', '/product/{id:\d+}', 'showProductById');
    $r->addRoute('GET', '/product/{slug:[a-zA-Z0-9_-]+}', 'showProductBySlug');
});

function showProductById($vars) {
    echo "Загружен товар с ID: " . $vars['id'];
}

function showProductBySlug($vars) {
    echo "Загружен товар со слагом: " . $vars['slug'];
}
// Результат при запросе GET /product/42
Загружен товар с ID: 42
// Результат при запросе GET /product/noviy-smartfon
Загружен товар со слагом: noviy-smartfon

Как добавить проверку существования товара и возвращать кастомные страницы 404?

Пример
$dispatcher = FastRoute\simpleDispatcher(function(RouteCollector $r) {
    $r->addRoute('GET', '/product/{id:\d+}', function($vars) {
        $product = getProductById($vars['id']);
        if (!$product) {
            http_response_code(404);
            echo "

Товар не найден

"; return; } // рендеринг шаблона echo "

{$product['name']}

"; }); }); // Функция поиска товара function getProductById($id) { $products = [ 1 => ['name' => 'Смартфон'], 2 => ['name' => 'Ноутбук'] ]; return $products[$id] ?? null; }
// Запрос GET /product/1

Смартфон

// Запрос GET /product/999

Товар не найден

(с кодом 404)

Как сгруппировать все маршруты для товаров в одном контроллере с помощью префикса?

Пример
use FastRoute\RouteCollector;

$dispatcher = FastRoute\simpleDispatcher(function(RouteCollector $r) {
    $r->addGroup('/product', function (RouteCollector $r) {
        $r->addRoute('GET', '', 'CatalogController::index');
        $r->addRoute('GET', '/{id:\d+}', 'ProductController::show');
        $r->addRoute('GET', '/{slug:[a-z0-9-]+}', 'ProductController::showBySlug');
    });
});
// Результат: URL /product вызывает каталог, /product/5 вызывает конкретный товар

Как применить middleware (например, авторизация) перед вызовом контроллера товара?

Пример
$container = new Container(); // PSR-11 контейнер
$dispatcher = FastRoute\simpleDispatcher(function(RouteCollector $r) use ($container) {
    $r->addRoute('GET', '/product/{id:\d+}', function($vars) use ($container) {
        $auth = $container->get('auth');
        if (!$auth->check()) {
            http_response_code(403);
            echo 'Доступ запрещен';
            return;
        }
        // вызов контроллера
        $controller = $container->get('productController');
        $controller->show($vars['id']);
    });
});

Для более гибкой реализации middleware рекомендуется использовать готовые PSR-15 библиотеки (например, Relay или Middlewares).

Маршрут товара с полным путем PHP - comments

En
Index php route product product path (php)