Skip to content

Instantly share code, notes, and snippets.

@frankdejonge
Created March 8, 2017 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frankdejonge/0ab1b9d386f7393e151538f0486ddd18 to your computer and use it in GitHub Desktop.
Save frankdejonge/0ab1b9d386f7393e151538f0486ddd18 to your computer and use it in GitHub Desktop.
Symfony Routing optimisation.
<?php
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
include __DIR__.'/vendor/autoload.php';
if (count($argv) < 2) {
die('Not enough arguments');
}
$className = $argv[1];
$routesFile = $argv[2] ?? 'routes';
$routes = include __DIR__.'/'. $routesFile .'.php';
$routeCollection = new RouteCollection();
foreach ($routes as $route) {
$routeCollection->add($route[1], new Route($route[0]));
}
$dumper = new PhpMatcherDumper($routeCollection);
file_put_contents(__DIR__.'/'.$routesFile.'_'.$className.'.php', $dumper->dump(['class' => $className]));
echo sprintf("Dumped routes into %s.php\n", $className);

In the given small route set

group avg max
master 0.81 1.56
pr 0.59 0.92

On a real life project with ~800 routes

group avg max
master 4.73 10.26
pr 1.07 2.42

This comparison is done against master which already includes the previous optimisation which brought routing times down from 7ms to 2,5ms.

<?php
return [
['/nl/', 'root_nl'],
['/nl/simple/match', 'simple_match_nl'],
['/nl/simple/{regex}', 'regex_match_nl'],
['/nl/nested/group/a_match', 'nested_group_a_nl'],
['/nl/nested/group/b_match', 'nested_group_b_nl'],
['/nl/grouped/a_match/{regex}', 'grouped_a_nl'],
['/nl/grouped/b_match', 'grouped_b_nl'],
['/nl/grouped/c_match/{regex}', 'grouped_c_nl'],
['/en/', 'root_en'],
['/en/simple/match', 'simple_match_en'],
['/en/simple/{regex}', 'regex_match_en'],
['/en/nested/group/a_match', 'nested_group_a_en'],
['/en/nested/group/b_match', 'nested_group_b_en'],
['/en/grouped/a_match/{regex}', 'grouped_a_en'],
['/en/grouped/b_match', 'grouped_b_en'],
['/en/grouped/c_match/{regex}', 'grouped_c_en'],
['/nl/nested/group/c_match', 'nested_group_c_nl'],
['/nl/nested/group/{regex}', 'nested_group_cutpoint_nl'],
['/nl/nested/group/a_match', 'nested_group_a_nl'],
['/nl/nested/group/b_match/{regex}', 'nested_group_b_nl'],
['/nl/nested/group/c_match', 'nested_group_c_nl'],
['/nl/grouped/d_match/{regex}', 'grouped_d_nl'],
['/nl/grouped/e_match', 'grouped_e_nl'],
['/nl/grouped/f_match', 'grouped_f_nl'],
['/en/nested/group/c_match', 'nested_group_c_en'],
['/en/nested/group/{regex}', 'nested_group_cutpoint_en'],
['/en/nested/group/a_match', 'nested_group_a_en'],
['/en/nested/group/b_match/{regex}', 'nested_group_b_en'],
['/en/nested/group/c_match', 'nested_group_c_en'],
['/en/grouped/d_match/{regex}', 'grouped_d_en'],
['/en/grouped/e_match', 'grouped_e_en'],
['/en/grouped/f_match', 'grouped_f_en'],
['/nl/deeper/nested/group/a_match', 'nested_group_a_deeper_nl'],
['/nl/deeper/nested/group/b_match/{regex}', 'nested_group_b_deeper_nl'],
['/nl/deeper/grouped/a_match', 'grouped_a_deeper_nl'],
['/nl/deeper/grouped/b_match/{regex}', 'grouped_b_deeper_nl'],
['/nl/deeper/grouped/c_match', 'grouped_c_deeper_nl'],
['/nl/deeper/nested/group/c_match', 'nested_group_c_deeper_nl'],
['/nl/deeper/nested/{regex}', 'nested_group_cutpoint_deeper_nl'],
['/en/deeper/nested/group/a_match', 'nested_group_a_deeper_en'],
['/en/deeper/nested/group/b_match/{regex}', 'nested_group_b_deeper_en'],
['/en/deeper/grouped/a_match', 'grouped_a_deeper_en'],
['/en/deeper/grouped/b_match/{regex}', 'grouped_b_deeper_en'],
['/en/deeper/grouped/c_match', 'grouped_c_deeper_en'],
['/en/deeper/nested/group/c_match', 'nested_group_c_deeper_en'],
['/en/deeper/nested/{regex}', 'nested_group_cutpoint_deeper_en'],
['/nl/deeper/nested/group/a_match', 'nested_group_a_deeper_nl'],
['/nl/deeper/nested/group/b_match/{regex}', 'nested_group_b_deeper_nl'],
['/nl/deeper/nested/group/c_match', 'nested_group_c_deeper_nl'],
['/nl/deeper/grouped/d_match', 'grouped_d_deeper_nl'],
['/nl/deeper/grouped/e_match/{regex}', 'grouped_e_deeper_nl'],
['/nl/deeper/grouped/f_match', 'grouped_f_deeper_nl'],
['/en/deeper/nested/group/a_match', 'nested_group_a_deeper_en'],
['/en/deeper/nested/group/b_match/{regex}', 'nested_group_b_deeper_en'],
['/en/deeper/nested/group/c_match', 'nested_group_c_deeper_en'],
['/en/deeper/grouped/d_match', 'grouped_d_deeper_en'],
['/en/deeper/grouped/e_match/{regex}', 'grouped_e_deeper_en'],
['/en/deeper/grouped/f_match', 'grouped_f_deeper_en'],
];
<?php
use Symfony\Component\Routing\RequestContext;
include __DIR__.'/vendor/autoload.php';
if (count($argv) < 2) {
die('Not enough arguments');
}
$className = $argv[1];
$routesFile = $argv[2] ?? 'routes';
$dumperClassFile = __DIR__ . '/' . $routesFile . '_'. $className . '.php';
if ( ! file_exists($dumperClassFile)) {
die('Matcher not found: '.$className);
}
include $dumperClassFile;
$context = new RequestContext();
$matcher = new $className($context);
$routes = include __DIR__.'/'. $routesFile .'.php';
$times = [];
foreach ($routes as $route) {
$path = preg_replace('#\{\w+\}#', 'XxX', $route[0]);
$start = microtime(true);
for ($i = 0; $i < 50000; ++$i) {
$matcher->match($path);
}
$time = microtime(true) - $start;
$times[$path] = $time;
fputcsv(STDERR, [$path, $time], "\t");
}
fputcsv(STDERR, ['avg', array_sum($times)/count($times)], "\t");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment