New in Symfony 4.1: Fastest PHP Router
February 15, 2018 • Published by Javier Eguiluz
Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.
Contributed by
Nicolas Grekas
in #26059 and
#26169.
Symfony 4 is the fastest PHP framework according to independent benchmarks, but we are continuously working on making it faster. In Symfony 4.1, we improved the Routing component to make it much faster when matching incoming URLs.
In web applications, routing is divided in two main operations: generation, which generates a URL from the given route and parameters; and matching, which decides which PHP code (i.e. controller) is executed as the response of an incoming URL.
In order to speed up the application, during the compilation phase Symfony generates a PHP class called "matcher" which contains all the route definitions optimized to match incoming URLs. For example, this is a snippet of the class generated for the Symfony Demo application:
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:
// ...
}
}
In Symfony 4.1 we refactored the matcher class generator based on the ideas shared in the following article: Fast request routing using regular expressions. The article explains the technique used by FastRoute, a routing library created by the genius PHP contributor Nikita Popov.
The basic idea is to avoid making separate preg_match()
calls for each route
and instead, combine all regular expressions into a single regular expression.
We also made many other big and small optimizations. If you are curious, see
the Pull Request #26059 and #26169 for all the details.
All in all, using the same Symfony Demo application example, this is how the
blog_post
route is matched now:
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),
);
// ...
}
In practice, combining all regular expressions improves URL matching performance by almost two orders of magnitude. In our benchmarks, Symfony 4.1 URL matching is 77 times faster than in previous Symfony versions. This also means that Symfony 4.1 router is now the fastest PHP router, beating FastRoute and all the other routing libraries.
Best of all: you don't need to make any change in your application to use this fast router. You just need to upgrade to Symfony 4.1 when it's released at the end of May 2018. Meanwhile you can test it in your applications and report any issue that you find.
Update: Nicolas has published two technical articles explaining in detail how the new router works:
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
If yes, we will able to specify what routes are more "important" (such as home page, front site, and at the end, back-office site) ?
http://www.rexegg.com/backtracking-control-verbs.html#mark
https://medium.com/@nicolas.grekas/making-symfonys-router-77-7x-faster-1-2-958e3754f0e1