Add valithor's static router concept

This commit is contained in:
Sky Johnson 2024-09-11 11:55:05 -05:00
parent 1bff49e3ba
commit 290fc105e9
2 changed files with 86 additions and 0 deletions

42
StaticRouter.php Normal file
View File

@ -0,0 +1,42 @@
<?php
class StaticRouter
{
public static $routes = [];
public static function add(string $method, string $route, callable $handler): void
{
$segments = array_map(function($segment) {
return str_starts_with($segment, ':') ? ':x' : $segment;
}, explode('/', trim($route, '/')));
$node = &self::$routes;
foreach ($segments as $segment) {
if ($segment === '') continue;
$node = &$node[$segment];
}
$node[$method] = $handler;
}
public static function lookup(array $node /* = &$this->routes */, string $method, string $uri): int|array
{
$uriSegments = explode('/', trim($uri, '/'));
$params = [];
if (isset($node[$method])) return [$node[$method], $params];
if (! $node2 = array_reduce($uriSegments, function ($carry, $segment) use (&$params) {
if (isset($carry[$segment])) return $carry[$segment];
if (isset($carry[':x'])) {
$params[] = $segment;
return $carry[':x'];
}
return null;
}, $node)) return 404;
if (isset($node2[$method])) return [$node2[$method], $params];
return 405;
}
}

44
tests/static.php Normal file
View File

@ -0,0 +1,44 @@
<?php
require_once 'tools.php';
require_once __DIR__ . '/../StaticRouter.php';
$r = new SegmentRouter();
// Big test
$big = readRoutes('big.txt');
foreach ($big as $route) {
[$method, $path] = $route;
$r->add($method, $path, function() {
return true;
});
}
echoTitle("Starting big lookups");
$start = microtime(true);
$reqs = 0;
for ($i = 0; $i < 1000000; $i++) {
$index = array_rand($big);
[$method, $path] = $big[$index];
$rstart = microtime(true);
$res = StaticRouter::lookup($r->routes, $method, $path);
if ($res === 404 || $res === 405) {
die("404 or 405\n");
}
$reqs += microtime(true) - $rstart;
}
echo "Time: " . Color::cyan(number_format(microtime(true) - $start, 10) . " s\n");
echo "Peak memory: " . Color::magenta(round(memory_get_peak_usage() / 1024, 1) . " kb\n");
echo "Avg/lookup: " . Color::yellow(number_format($reqs / 1000000, 10) . " s\n");
function readRoutes(string $file): array
{
$array = [];
$routes = file($file);
foreach ($routes as $route) {
[$method, $path] = explode(' ', $route);
$path = trim($path);
$array[] = [$method, $path];
}
return $array;
}