真正轻量的路由组件只有nikic/fast-route和noahbuscher/macaw:前者支持psr-7、路径约束与中间件,后者单文件无依赖但不支持正则约束且易受运行时环境影响。

装哪个路由组件才真轻量
别碰 symfony/routing——它自带 YAML 解析、表达式语言、缓存生成器,哪怕只定义 3 条路由,也会多加载 1MB+ 类、拖慢启动 3–5ms。真正轻量的选项只有两个:nikic/fast-route(纯数组编译 + 正则匹配)或 noahbuscher/macaw(单文件、无依赖、适合教学)。
选 fast-route 的前提是你需要 PSR-7 兼容、支持路径参数约束、后续可能加中间件;选 macaw 就图个快:5 分钟跑通 GET /hello → echo "ok",但不支持 {id:\d+} 这类正则约束。
-
composer require nikic/fast-route—— 注意别漏掉nikic/前缀,否则报Could not find package fast-route -
composer require noahbuscher/macaw—— 不要写dev-master,直接用最新稳定版(v2.1+ 支持 PHP 8.2) - 装完立刻运行
composer show nikic/fast-route或composer show noahbuscher/macaw,确认版本号和 PHP 版本兼容(fast-route v2.x要求 PHP ≥ 8.0)
装完就 404?你没配 Web 服务器转发
路由组件只做匹配,不接管 HTTP 请求。Apache/Nginx 根本不知道该把 /user/123 转给你的 index.php,所以浏览器访问永远 404。
必须手动配置伪静态规则:
- Apache:在
.htaccess里加RewriteRule ^(.*)$ index.php [QSA,L],并确保mod_rewrite已启用 - Nginx:在 server block 中加
try_files $uri $uri/ /index.php?$query_string; - PHP 内置服务器(仅开发用):
php -S 127.0.0.1:8000 -t public/ router.php,其中router.php必须返回FALSE才能触发 fallback
注意:macaw 默认要求路径带前导斜杠(Macaw::get('/hello', ...)),而 fast-route 的 simpleDispatcher() 接收的是原始路径字符串,别传 $_SERVER['PATH_INFO']——它在 Nginx + PHP-FPM 下不可靠,改用 $request->getUri()->getPath()。
FastRoute 怎么安全接 PSR-7 请求对象
fast-route 本身不绑定任何 HTTP 抽象层,它只返回一个三元数组 $routeInfo。你要自己桥接 PSR-7,常见坑是忘了截掉 base path。
比如部署在 /api/v1 下,请求 URL 是 https://example.com/api/v1/users/123,那么 $request->getUri()->getPath() 返回的是 /api/v1/users/123,直接传给 dispatch() 会全部匹配失败。
- 正确做法:
$path = ltrim($request->getUri()->getPath(), '/api/v1');,再传给$dispatcher->dispatch($method, $path) - 路径参数必须显式声明:
/user/{id:\d+}比/user/{id}安全,否则/user/new可能被误匹配,导致 404 - 别在闭包里写业务逻辑:
['UserHandler', 'show']比function ($id) { echo "user $id"; }更可控,也方便后续加中间件
Macaw 为什么简单却容易踩 runtime 坑
macaw 看似一行 Macaw::get('/test', fn() => 'ok') 就完事,但它依赖全局 $_SERVER 和 $_GET,且不校验 HTTP 方法大小写。
- Apache mod_php 下正常,但 Nginx + PHP-FPM 时
$_SERVER['REQUEST_METHOD']可能是小写get,而Macaw::dispatch()只认大写,导致所有 POST/PUT 路由失效 - 解决办法:在
dispatch()前手动转大写:$_SERVER['REQUEST_METHOD'] = strtoupper($_SERVER['REQUEST_METHOD']); - 它不处理路由参数自动注入,
Macaw::get('/user/(:num)', fn($id) => ...)中的$id是靠func_get_args()拿的,一旦你启用了 OPcache 或代码混淆,参数名丢失,$id就变null - 更稳写法:
Macaw::get('/user/(:num)', function () { $args = func_get_args(); $id = $args[0]; ... });
真正轻量不是代码行数少,而是依赖链干净、行为可预测。如果你连 $_SERVER 都不敢信,那就别用 macaw —— 直接上 fast-route + nyholm/psr7,多写 3 行,少 debug 2 小时。











