PHP自定义Router无法正确匹配路由,请求故障排查
问题排查与解决方案
核心问题分析
你的路由实现存在三个关键问题:
- 路由注册逻辑错误:原
get方法每次调用都会立即检查请求路径,不匹配就直接触发404并终止脚本,导致后续注册的路由永远无法执行。比如访问/user时,第一个get("/", ...)会因路径不匹配直接抛出404,不会走到/user的路由判断。 - 动态查询参数匹配缺失:原代码的
getPath方法会剥离URL中的查询字符串,因此/user?id={[0-9]}这种带查询参数的路由永远无法匹配,同时也没有实现查询参数的正则校验逻辑。 - 期望输出未触发:原代码仅当
callback是字符串时才输出Succesfuly navigated to {$route},但你注册的路由用的都是匿名函数,因此不会触发这段输出。
修改后的Router.php
<?php class Router { private $routes = []; // 存储所有注册的路由规则 public function get($route, $callback) { // 拆分路由的路径与查询参数规则 $routeParts = parse_url($route); $routePath = $routeParts['path'] ?? $route; $queryRules = []; // 解析路由中的查询参数正则规则 if (!empty($routeParts['query'])) { parse_str($routeParts['query'], $queryParams); foreach ($queryParams as $key => $regex) { $queryRules[$key] = $regex; } } $this->routes[] = [ 'path' => $routePath, 'queryRules' => $queryRules, 'callback' => $callback ]; } // 统一处理请求分发 public function dispatch() { $currentPath = $this->getPath(); $currentQuery = $_GET; // 遍历所有路由寻找匹配项 foreach ($this->routes as $route) { // 先匹配路径部分 if ($currentPath !== $route['path']) { continue; } // 校验查询参数是否符合规则 $queryMatch = true; foreach ($route['queryRules'] as $key => $regex) { if (!isset($currentQuery[$key]) || !preg_match("/^{$regex}$/", $currentQuery[$key])) { $queryMatch = false; break; } } if (!$queryMatch) { continue; } // 匹配成功,输出期望内容并执行回调 echo "Succesfuly navigated to {$route['path']} "; echo call_user_func($route['callback']); exit(); } // 无匹配路由,返回404 $this->notFound(); } // 获取去除查询字符串的路径 private function getPath() { $path = $_SERVER['REQUEST_URI'] ?? '/'; $paramPosition = strpos($path, "?"); return $paramPosition === false ? $path : substr($path, 0, $paramPosition); } private function notFound() { http_response_code(404); echo "Not Found"; exit(); } } ?>
修改后的index.php
<?php include_once './core/Router.php'; $router = new Router(); $router->get("/", function() { return "Path / traversed"; }); $router->get("/user", function() { return "Path /user traversed"; }); // 注册带数字id查询参数的路由 $router->get("/user?id=[0-9]+", function(){ return "Path /user with numeric id traversed"; }); // 触发路由分发 $router->dispatch(); ?>
关键修改说明
- 路由收集与延迟匹配:新增
$routes数组存储所有路由,get方法仅负责添加路由规则,新增dispatch方法统一处理请求,遍历所有路由寻找匹配项,避免了原代码提前终止脚本的问题。 - 查询参数校验逻辑:通过
parse_url拆分路由的路径和查询参数规则,匹配时先校验路径,再检查查询参数是否符合正则要求,实现了/user?id=数字的匹配逻辑。 - 输出逻辑修复:在路由匹配成功后统一输出期望的导航提示,回调函数返回内容而非直接输出,保证输出顺序符合预期。
内容的提问来源于stack exchange,提问作者mitas1c
相关产品推荐
相关产品推荐

