Нужна помощь с поиском нестатических роутов

Ради обучения пишу свой мини mvc фреймворк. Щас на роутинге. Вот увидел как у симфони можно задать нестатический роут, сразу с доп регуляркой для параметра, и хочу реализовать подобное:

@Route("/test/foo/{slug}/bar/{id<\d+>}", name="test")

Тут, к примеру, нужно достать 2 параметра slug, id, для slug регулярка по умолчанию (напр. [a-zA-Z0-9]+), а для id та что в <>, тут будет \d+.

Роуты храню в таком виде:

$routes['get']['/contact'] = [MainController::class, 'contact'];
$routes['post']['/contact'] = [MainController::class, 'contact'];
$routes['get']['/articles/{slug}/comments/{id<\d+>}'] = [MainController::class, 'test'];

Статические роуты искать не проблема:

public function run() : Response
{
    $method = $this->request->getMethod();
    $path = $this->request->getPath();
    $params = [];

    $route = $this->routes[$method][$path] ?? false;

    if (!$route) {
        $route = $this->findUnstatic($this->routes[$method], $path, $params);
    }
    
    [$controller, $action] = $route;
    $controllerInstance = new $controller();
    
    return call_user_func([$controllerInstance, $action], $this->request , ...$params);
}

Нужна помощь с реализацией метода findUnstatic($routes, $path, &$params) {}, который вернет массив, где записан контроллер и метод для вызова, напр. [MainController::class, 'test'], если роут будет /articles/{slug}/comments/{id<\d+>}, а также запишет параметры slug, id в массив $params.


Ответы (1 шт):

Автор решения: Taras Koval

Сделал сам свою задачу, правда не уверен в производительности такого варианта. Если ктото знает как можно улучшить, буду рад предложениям.

private function findUnstatic($routes, $path, &$params)
{
    foreach ($routes as $route => $controller) {
        if (preg_match($this->routeCompile($route), $path, $params)) {
            array_shift($params);
            return $controller;
        }
    }
    
    return false;
}

private function routeCompile($route): string
{
    $default = '(\w+)';
    
    return preg_replace_callback('~{(.+?)}~', function ($match) use ($default) {
        return preg_match('~<(.+?)>~', $match[1], $regex)? "($regex[1])" : $default;
    }, "~^$route$~");
}
→ Ссылка