Contributed by
Nicolas Grekas
in #26059 and
#26169.
依照独立跑分,Symfony 4 是 最快的框架,但我们持续努力令其更快。在 Symfony 4.1 中,我们改进了 Routing组件 让它在匹配到到访URL时变得更快。
在web程序中,路由被切分为两个主要的动作: generation(生成),根据给定的路由及其参数生成URL;以及 matching(匹配),决定哪个PHP代码(即controller)会被执行以作为到访URL的响应。
为了在编译阶段加速程序,Symfony 生成了一个名为 "matcher" 的PHP类,包含全部路由定义,为到访的URL而专门优化。例如,这是一个为 Symfony 演示程序 而生成的码段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // var/cache/prod/srcProdDebugProjectContainerUrlMatcher.php
class srcProdDebugProjectContainerUrlMatcher
{
// ...
public function match($rawPathinfo)
{
// ...
// blog_post
if (preg_match('#^/(?P<_locale>en|fr|de|es)/blog/posts/(?P<slug>[^/]++)$#s', $pathinfo, $matches)) {
if ('GET' !== $canonicalMethod) {
$allow[] = 'GET';
goto not_blog_post;
}
return $this->mergeDefaults(array_replace($matches, array('_route' => 'blog_post')), array ( '_controller' => 'App\\Controller\\BlogController::postShow', '_locale' => 'en',));
}
not_blog_post:
// ...
}
} |
根据以下文章中的点子,在 Symfony 4.1 中我们重构了 matcher 类的生成器: Fast request routing using regular expressions。本来解释了 FastRoute 中使用的技巧,这是由天才的PHP贡献者 Nikita Popov 所写的路由类库。
基本想法是,避免在每一个路由中依次调用 preg_match()
,取而代之的是,把全部正则合并为一个单一正则。我们也做了其他大大小小的优化。如果你对此感到好奇,参考 Pull Request #26059 和 #26169 以了解细节。
总之,若以相同的 Symfony 演示程序为例,下面是今日 blog_post
路由如何被匹配到的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | $regexList = array(
0 => '{^(?'
.'|/(en|fr|de|es)/admin/post/?(*:82)'
.'|/(en|fr|de|es)/admin/post/new(*:166)'
.'|/(en|fr|de|es)/admin/post/(\\d+)(*:253)'
.'|/(en|fr|de|es)/admin/post/(\\d+)/edit(*:345)'
.'|/(en|fr|de|es)/admin/post/([^/]++)/delete(*:442)'
.'|/(en|fr|de|es)/blog/?(*:519)'
.'|/(en|fr|de|es)/blog/rss\\.xml(*:603)'
.'|/(en|fr|de|es)/blog/page/([1-9]\\d*)(*:694)'
.'|/(en|fr|de|es)/blog/posts/([^/]++)(*:784)'
.'|/(en|fr|de|es)/blog/comment/([^/]++)/new(*:880)'
.'|/(en|fr|de|es)/blog/search(*:962)'
.'|/(en|fr|de|es)/login(*:1038)'
.'|/(en|fr|de|es)/logout(*:1116)'
.'|/(en|fr|de|es)?(*:1188)'
.')$}sD',
);
foreach ($regexList as $offset => $regex) {
// ...
default:
$routes = array(
// ...
784 => array(array('_route' => 'blog_post', '_controller' => 'App\\Controller\\BlogController::postShow', '_locale' => 'en'), array('_locale', 'slug'), array('GET' => 0), null),
);
// ...
} |
实践中,合并全部正则,把URL匹配时的性能给提高了两个数量级。在我们的基准测试中,Symfony 4.1 URL 匹配能力77倍快 于之前的 Symfony 版本。这也意味着 Symfony 4.1 的路由是最快的PHP路由,打败了 FastRoute 和其他所有 routing libraries(路由类库)。
最强的一点: 你毋须在程序中做任何改变 即可使用这个最快的路由系统。只需在 end of May 2018 发布时升级到 Symfony 4.1 即可。同时你还可以在自己的程序中测试它,并把发现的问题上报。
Update: Nicolas 发布了两篇技术文章来详细解释新 router 是如何运作的: