单独安装 laminas/laminas-router 无法构建高度可扩展的路由系统,因其仅提供路由匹配功能,缺乏 psr-7 请求响应支持、psr-15 中间件调度及自动分发逻辑,必须搭配 laminas-diactoros、laminas-stratigility 和 laminas-http-handler-runner 三者协同工作。

直接装 laminas/laminas-router 不足以构建“高度可扩展的路由系统”——它只是个基础路由解析器,没中间件调度、没 PSR-7 请求/响应封装、没自动分发逻辑。真正可扩展的路由必须搭配其他组件协同工作。
为什么单独 require laminas/laminas-router 会卡在 dispatch 环节
装完后你写好路由配置、注册了 Route 对象,但调用 $router->match($request) 只返回一个 RouteResult,后续怎么执行控制器?怎么注入依赖?怎么跑中间件?laminas-router 本身不处理这些。它只回答“这个 URL 匹配哪条路由”,不负责“接下来干什么”。
- 常见错误现象:
Call to undefined method Laminas\Router\Http\TreeRouteStack::dispatch()—— 因为该类根本没有dispatch()方法 - 必须手动判断
RouteResult::isSuccess(),再自己提取参数、实例化控制器、调用方法、构造响应 - 没有 PSR-15 兼容层,无法接入 Stratigility、Mezzio 或自定义中间件栈
要真正可扩展,必须补全这三块依赖
仅靠 laminas/laminas-router 是断腿走路。下面三个包缺一不可,且顺序不能乱:
-
composer require laminas/laminas-diactoros:提供 PSR-7 的ServerRequest和Response实现,laminas-router的match()方法只认这种请求对象 -
composer require laminas/laminas-stratigility:提供 PSR-15 中间件调度器(MiddlewarePipe),让路由结果能链式流转到下游中间件或最终处理器 -
composer require laminas/laminas-http-handler-runner:把中间件返回的ResponseInterface正确输出到 SAPI(如 Apache/CLI),否则你只能 echo 字符串
漏掉任意一个,你就得手写 request 构造、response 发送、中间件循环——这不是“可扩展”,是重造轮子。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
实际路由分发代码长什么样(不是伪代码)
以下是最小可行的可扩展分发逻辑,放在 public/index.php 中:
<?php require __DIR__ . '/../vendor/autoload.php';
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\Router\Http\TreeRouteStack;
use Laminas\Router\Http\RouteMatch;
use Laminas\Stratigility\MiddlewarePipe;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
// 1. 构建请求
$request = ServerRequestFactory::fromGlobals($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
// 2. 配置路由
$router = TreeRouteStack::factory([
'routes' => [
'home' => [
'type' => 'Literal',
'options' => ['route' => '/', 'defaults' => ['controller' => 'Home', 'action' => 'index']],
],
'user' => [
'type' => 'Segment',
'options' => ['route' => '/user[/:id]', 'defaults' => ['controller' => 'User', 'action' => 'show']],
],
],
]);
// 3. 匹配路由
$routeMatch = $router->match($request);
if (!$routeMatch instanceof RouteMatch) {
$response = new \Laminas\Diactoros\Response();
$response->getBody()->write('404 Not Found');
(new SapiEmitter())->emit($response);
exit;
}
// 4. 注入路由参数到 request(关键!否则控制器拿不到 :id)
$request = $request->withAttribute('route-match', $routeMatch);
// 5. 构建中间件管道(此处简化,真实项目应注册多个中间件)
$pipe = new MiddlewarePipe();
$pipe->pipe(function ($request, $handler) {
$routeMatch = $request->getAttribute('route-match');
$controller = $routeMatch->getParam('controller');
$action = $routeMatch->getParam('action');
// 这里才真正分发到业务逻辑(可替换成 DI 容器解析)
$response = match ("{$controller}/{$action}") {
'Home/index' => (new \App\Controller\HomeController())->index($request),
'User/show' => (new \App\Controller\UserController())->show($request, $routeMatch->getParam('id')),
default => new \Laminas\Diactoros\Response(),
};
return $response;
});
// 6. 执行并发送响应
$response = $pipe->process($request, new \Laminas\Stratigility\EmptyPipeline());
(new SapiEmitter())->emit($response);
注意第 4 步:$request->withAttribute() 是 PSR-7 不可变对象的关键操作,漏掉这句,下游就完全不知道匹配了哪条路由、参数是什么——这是最容易被忽略的胶水逻辑。
别碰 illuminate/routing,除非你已在 Laravel 生态里
有人想抄 Laravel 的 Illuminate\Routing\Router,但单独 composer require illuminate/routing 几乎必然失败:
- 它强依赖
illuminate/container、illuminate/http、illuminate/events等至少 7 个包,版本稍不一致就报Class not found - 它的路由注册机制(
Route::get()静态调用)和laminas-router的配置数组方式冲突,混用会导致行为不可预测 - 如果你没用 Laravel 的服务容器和生命周期管理,硬塞
illuminate/routing只会让启动流程更脆弱
真要 Laravel 风格语法,不如直接上 Mezzio + mezzio-laminasrouter,它把 laminas-router 封装成 PSR-15 中间件,还自带配置驱动和错误处理——这才是面向可扩展的设计。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










