提问人:Omar Abdulwahhab 提问时间:10/19/2023 更新时间:10/19/2023 访问量:33
使用可选参数实现 PHP 路由器
Implementing a PHP Router with Optional Parameters
问:
我一直在努力实现一个简单的PHP路由器,并设法使它使用所需的参数。但是,我正在努力实现可选参数,但我失败了。为了清楚起见,我将提供相关代码。
首先,这是我的索引.php:
<?php
$app->route->get("/user/:id/?post_id", [SiteController::class, "contact"]);
?>
在上面的代码中,我使用冒号 (:id) 作为必需参数,使用问号 (?post_id) 作为可选参数。
其次,这是我的 Router 类:
class Router {
public function resolve() {
$method = $this->request->getMethod();
$url = $this->request->getUrl();
foreach ($this->router[$method] as $routeUrl => $target) {
$pattern = preg_replace('/\/:([^\/]+)/', '/(?P<$1>[^/]+)', $routeUrl);
if (preg_match('#^' . $pattern . '$#', $url, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
call_user_func([new $target[0], $target[1]], ...array_values($params));
exit();
}
}
throw new \Exception();
}
}
我需要帮助来解决实现可选参数的谜团。任何帮助将不胜感激。谢谢!
答:
0赞
ThW
11/21/2023
#1
下面是一个函数,用于将路由路径模式编译为具有命名捕获组的正则表达式。它使用回调函数根据指标字符返回不同的模式。
function compileRoutePattern(string $route): string {
// replace parameter syntax with named capture groups
return '(^'.preg_replace_callback(
'((?<prefix>^|/)(?:(?<indicator>[:?])(?<name>[\w\d]+)|[^/]+))',
function($match) {
return match ($match['indicator'] ?? '') {
// mandatory parameter
':' => sprintf('(?:%s(?<%s>[^/]+))', $match['prefix'], $match['name']),
// optional parameter
'?' => sprintf('(?:%s(?<%s>[^/]+))?', $match['prefix'], $match['name']),
// escape anything else
default => preg_quote($match[0], '(')
};
},
$route
).')i';
}
下一步是匹配路径并仅返回命名的捕获组(而不是数字键)。
function matchRoute(string $path, string $route): ?array {
// compile route into regex with named capture groups
$pattern = compileRoutePattern($route);
// match
if (preg_match($pattern, $path, $match)) {
// filter numeric keys from match
return array_filter(
$match,
fn($key) => is_string($key),
ARRAY_FILTER_USE_KEY
);
}
return null;
}
提示:我使用模式分隔符来避免冲突。将它们视为组 0。()
评论