很久之前在写RidPT的时候,我就在考虑使用社区中更为优质的组件来替换原 MixPHP 中自带的一些组件。而路由部分中 symfony/routing 可能是我之前最想尝试的,因为目前RidPT中使用Symfony/HttpFoundation构建了请求和响应组件(甚至有段时间我觉得我在另外构建一个symfony,而且还没别人官方的好,其对swoole异步/协程的支持也均未测试)。然而接触文档之后,发现配置起来相当麻烦,远不如我在symfony应用中使用Annotations方法来的简便(因为杂活都让框架给做了)。
此外,对照文档,我们需要首先根据Request构造新的RequestContext对象,然后传入UrlMatcher并调用其match方法。虽然swoole常驻模式可以减少前面路由规则生成部分,但是后续对请求处理的部分,依然需要构造新的对象,造成无端的时间和空间浪费。且Symfony中并没有Middleware的概念,而是使用Event Dispatch的整体流程对请求-响应进行调度,为此再引入多个symfony组件似乎得不偿失。
1 | use App\Controller\BlogController; |
之后我便一直在关注 nikic/FastRoute 的东西。但一开始FastRoute本身不太了解,认为很难将FastRoute和目前应用中中间件部分相结合,另一方面就是之前有些排斥直接使用函数返回的形式对路由进行定义(真香)。于是找了一些基于FastRoute的扩展repo来学习,例如:
- https://route.thephpleague.com/
- easy-swoole的http组件、hyperf的路由组件等基于swoole框架的路由组件
然而league/route的实现基于PSR-7 HTTP Message,已有的Symfony\Component\HttpFoundation\{Request,Response}都不是相关继承实现,而且内部较为复杂,一时难以理解。而其他swoole框架的虽稍好理解,但也很难直接的拿来主义。就这样搁置了一阵子。
这段时间正好有些空闲,对原有依赖注入部分进行了替换(改成PHP-DI),便重新拾起了这一部分,看看能不能有更好的方法将FastRoute与项目进行联系。
回到FastRoute的官方示例中,
1 | require '/path/to/vendor/autoload.php'; |
并结合一些issue,我才知道,我对handler本身的理解存在偏差,一开始我以为handler只能存放类似 [AbstractController::class,'action']的动作,但是其实并不是这样的。
FastRoute在返回的$routeInfo[1]中会将定义路由时 addRoute($method,$path,$handler)的第三个参数原模原样返回。在其issue的 #186,#147 中,我觉得我找到了相应添加middleware的方法。
Nevraxe/Cervo在其Router对象中,对FastRoute进行了进一步封装,但我觉得稍有过度。直接对原 FastRoute\RouteCollector 进行继承扩展似乎更为合适。最终结果如下:
1 |
|
从中可以看到,我增加了一个addMiddleware方法,并依此扩展了原addRoute方法。在此基础上即可生成对应的可返回中间件的FastRoute对象。
1 | $dispatcher = \FastRoute\simpleDispatcher($route_def, [ |
而对应路由配置文件如下:
1 |
|
