dump(), TREES . 'blog.txt'); echoTitle("Starting blog lookups"); runIterations(10000, $r, $blog); runIterations(100000, $r, $blog); runIterations(1000000, $r, $blog); unset($blog); // Github lookups $r->clear(); $github = readAndAddRoutes(ROUTES . 'github.txt', $r); writeRoutesToFile($r->dump(), TREES . 'github.txt'); echoTitle("Starting github lookups"); runIterations(10000, $r, $github); runIterations(100000, $r, $github); runIterations(1000000, $r, $github); unset($github); // Big lookups $r->clear(); $big = readAndAddRoutes(ROUTES . 'big.txt', $r); writeRoutesToFile($r->dump(), TREES . 'big.txt'); echoTitle("Starting big lookups"); runIterations(10000, $r, $big); runIterations(100000, $r, $big); runIterations(1000000, $r, $big); unset($big); // Parameter testing $r->clear(); echoTitle("Testing parameters"); $routes = [ ['GET', '/blog/:id', function($id) { echo $id."\n"; }], ['GET', '/blog/:id/:slug', function($id, $slug) { echo $id . ' - ' . $slug."\n"; }], ['GET', '/blog/:id/:slug/:page', function($id, $slug, $page) { echo $id . ' - ' . $slug . ' - ' . $page."\n"; }], ['GET', '/blog/:id/:slug/:page/:extra', function($id, $slug, $page, $extra) { echo $id . ' - ' . $slug . ' - ' . $page . ' - ' . $extra."\n"; }], ]; array_walk($routes, fn($route) => $r->add($route[0], $route[1], $route[2])); for ($i = 0; $i < 10; $i++) { [$method, $uri] = $routes[array_rand($routes)]; // Generate some random parameters $uri = str_replace(':id', rand(1, 100), $uri); $uri = str_replace(':slug', 'slug-' . rand(1, 100), $uri); $uri = str_replace(':page', rand(1, 100), $uri); $uri = str_replace(':extra', 'extra-' . rand(1, 100), $uri); $res = $r->lookup($method, $uri); if ($res['code'] !== 200) { echo "Failed to handle request for $uri - $res\n"; exit(1); } $res['handler'](...$res['params']); } $r->clear(); echoTitle('Testing root node'); $r->add('GET', '/', function() { echo "Root node is gtg!\n"; }); $res = $r->lookup('GET', '/'); if ($res['code'] !== 200) { echo "Failed to handle request for /\n"; exit(1); } $res['handler'](); echo "\n".Color::blue("āœ”ļø Done!")."\n\n"; function echoTitle(string $title) { echo "\n"; echo Color::bold(Color::black("===============================================================")) . "\n"; echo "\n"; echo Color::bold(Color::blue($title))."\n"; echo "\n"; echo Color::bold(Color::black("===============================================================")) . "\n"; echo "\n"; } function readAndAddRoutes(string $file, &$r): array { return array_map(function($route) use ($r) { [$method, $path] = explode(' ', $route); $path = trim($path); $r->add($method, $path, fn() => true); return [$method, $path]; }, file($file)); } function runIterations(int $iterations, $r, array $routes) { echo "\nšŸš€ Running $iterations iterations...\n"; $start = microtime(true); // start the timer $reqs = 0; // track the timing of lookups $longest = 0; // track the longest lookup time $shortest = 0; // track the shortest lookup time $longestRoute = ''; $shortestRoute = ''; for ($i = 0; $i < $iterations; $i++) { // pick a random route from the array [$method, $path] = $routes[array_rand($routes)]; // replace all :params/ with random values $uri = preg_replace_callback('/:(\w+)/', function($matches) { return rand(1, 100); }, $path); $start2 = microtime(true); // start the timer for the lookup $res = $r->lookup($method, $uri); // run the lookup $reqs += microtime(true) - $start2; // add this lookup time if ($shortest == 0 || microtime(true) - $start2 < $shortest) { $shortest = microtime(true) - $start2; // track the shortest lookup time $shortestRoute = "$method $uri"; } if (microtime(true) - $start2 > $longest) { $longest = microtime(true) - $start2; // track the longest lookup time $longestRoute = "$method $uri"; } // if any error was encountered, print it and exit if ($res['code'] !== 200) { echo Color::red("Failed to handle request.\n$method {$res['code']}\n"."ā”œā”€ URI: $uri\nā””ā”€ Path: $path\n"); echo Color::yellow("Completed $i iterations before failure.\n"); exit(1); } } echo Color::blue("āœ”ļø Done!")."\n"; // echo peak memory usage echo "Peak memory: " . Color::magenta(round(memory_get_peak_usage() / 1024, 1) . " kb\n"); // total time used for this run echo "Time: " . Color::cyan(number_format(microtime(true) - $start, 10) . " s\n"); // echo the average time per request echo "Avg/lookup: " . Color::yellow(number_format($reqs / $iterations, 10) . " s\n"); // echo the shortest lookup time echo "Shortest lookup: " . Color::green(number_format($shortest, 10) . " s\n"); // echo the longest lookup time echo "Longest lookup: " . Color::red(number_format($longest, 10) . " s\n"); echo Color::black("==============================================") . "\n"; // echo the longest and shortest routes echo "Shortest route: " . Color::green($shortestRoute) . "\n"; echo "Longest route: " . Color::red($longestRoute) . "\n"; } // take a route tree (array) and store it in a file to be read function writeRoutesToFile(array $routes, string $file) { // Clear the file before writing file_put_contents($file, ''); $fp = fopen($file, 'w'); // write a / to the first line of the file fwrite($fp, "/\n"); // Start writing from the root level with an indentation of 0 and no prefix writeNode($routes, 0, '', $fp); fclose($fp); } function writeNode($node, $indent, $prefix, $fp) { $totalItems = count($node); $currentItem = 0; foreach ($node as $key => $value) { $currentItem++; $isLastChild = ($currentItem === $totalItems); $connector = $isLastChild ? 'ā””ā”€ā”€ ' : 'ā”œā”€ā”€ '; $key = empty($key) ? '/' : $key; // Write the current node's key with the tree symbol fwrite($fp, $prefix . $connector . $key . "\n"); // If the value is an array, it represents a child node, so recurse if (is_array($value)) { $newPrefix = $prefix . ($isLastChild ? ' ' : 'ā”‚ '); writeNode($value, $indent + 1, $newPrefix, $fp); } } }