Condense the Router to just the SegmentRouter, and format as a Composer package
This commit is contained in:
parent
9e35166eea
commit
55306b27b9
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
tests/trees
|
||||||
|
|
||||||
|
/vendor/
|
|
@ -1,6 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
interface Router {
|
|
||||||
public function add(string $method, string $route, callable $handler): Router;
|
|
||||||
public function lookup(string $method, string $uri): array;
|
|
||||||
}
|
|
254
SimpleRouter.php
254
SimpleRouter.php
|
@ -1,254 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class SimpleRouter
|
|
||||||
{
|
|
||||||
private static array $routes = [];
|
|
||||||
private static $pathNotFound;
|
|
||||||
private static $methodNotAllowed;
|
|
||||||
private static string $defaultConstraint = '([\w\-]+)';
|
|
||||||
private static string $currentPrefix = '';
|
|
||||||
private static string $lastInsertedRoute = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A quick static function to register a route in the router. Used by the shorthand methods as well.
|
|
||||||
*
|
|
||||||
* @param string $route The path to be used as the route.
|
|
||||||
* @param callable|string $action Either a callable to be executed, or a string reference to a method.
|
|
||||||
* @param string|array $methods The HTTP verb(s) this route accepts.
|
|
||||||
* @return Router
|
|
||||||
*/
|
|
||||||
public static function add(string $route, callable|string $action, string|array $methods = 'GET')
|
|
||||||
{
|
|
||||||
// If a prefix exists, prepend it to the route
|
|
||||||
if (!empty(self::$currentPrefix)) {
|
|
||||||
$route = self::$currentPrefix.$route;
|
|
||||||
}
|
|
||||||
|
|
||||||
$trimmed = self::trimRoute($route);
|
|
||||||
|
|
||||||
self::$routes[] = [
|
|
||||||
'route' => $trimmed,
|
|
||||||
'action' => $action,
|
|
||||||
'methods' => $methods,
|
|
||||||
'constraints' => []
|
|
||||||
];
|
|
||||||
|
|
||||||
self::$lastInsertedRoute = $trimmed;
|
|
||||||
|
|
||||||
return new self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand function to define a GET route
|
|
||||||
*
|
|
||||||
* @param string $route
|
|
||||||
* @param callable $action
|
|
||||||
* @return Router
|
|
||||||
*/
|
|
||||||
public static function get(string $route, callable $action)
|
|
||||||
{
|
|
||||||
return self::add($route, $action, 'GET');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default function to define a POST route
|
|
||||||
*
|
|
||||||
* @param string $route
|
|
||||||
* @param callable $action
|
|
||||||
* @return Router
|
|
||||||
*/
|
|
||||||
public static function post(string $route, callable $action)
|
|
||||||
{
|
|
||||||
return self::add($route, $action, 'POST');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all routes currently registered
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getAllRoutes()
|
|
||||||
{
|
|
||||||
return self::$routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines an action to be called when a path isn't found - i.e. a 404
|
|
||||||
*
|
|
||||||
* @param callable $action
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function pathNotFound(callable $action)
|
|
||||||
{
|
|
||||||
self::$pathNotFound = $action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines an action to be called with a method isn't allowed on a route - i.e. a 405
|
|
||||||
*
|
|
||||||
* @param callable $action
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function methodNotAllowed(callable $action)
|
|
||||||
{
|
|
||||||
self::$methodNotAllowed = $action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redefine the default constraint for route parameters. Default is '([\w\-]+)'
|
|
||||||
*
|
|
||||||
* @param string $constraint The RegEx you want parameters to adhere to by default. Defaults to '([\w\-]+)'
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function setDefaultConstraint(string $constraint = '([\w\-]+)')
|
|
||||||
{
|
|
||||||
self::$defaultConstraint = $constraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function trimRoute(string $route): string
|
|
||||||
{
|
|
||||||
$route = trim(trim($route), '/');
|
|
||||||
return "/$route";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a callable that defines routes, and adds a prefix to them.
|
|
||||||
*
|
|
||||||
* @param string $prefix The prefix you want added to the routes.
|
|
||||||
* @param callable $routes A function that defines routes.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function prefix(string $prefix, callable $routes)
|
|
||||||
{
|
|
||||||
self::$currentPrefix = $prefix;
|
|
||||||
|
|
||||||
$routes();
|
|
||||||
|
|
||||||
self::$currentPrefix = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define a constraint for a route parameter. If only passing one parameter,
|
|
||||||
* provide the parameter name as first argument and constraint as second. If
|
|
||||||
* adding constraints for multiple parameters, pass an array of 'parameter' => 'constraint'
|
|
||||||
* pairs.
|
|
||||||
*
|
|
||||||
* @param string|array $parameter
|
|
||||||
* @param string $constraint
|
|
||||||
* @return Router
|
|
||||||
*/
|
|
||||||
public static function with(string|array $parameter, string $constraint = '')
|
|
||||||
{
|
|
||||||
$last = self::$lastInsertedRoute;
|
|
||||||
|
|
||||||
if (is_array($parameter)) {
|
|
||||||
foreach ($parameter as $param => $constraint) {
|
|
||||||
self::$routes[$last]['constraints'][$param] = $constraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new self;
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$routes[$last]['constraints'][$parameter] = $constraint;
|
|
||||||
|
|
||||||
return new self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tokenizes the given URI using our constraint rules and returns the tokenized URI
|
|
||||||
*
|
|
||||||
* @param string $uri
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function tokenize(string $uri, array $constraints)
|
|
||||||
{
|
|
||||||
$constraintKeys = array_keys($constraints);
|
|
||||||
|
|
||||||
preg_match_all('/(?:{([\w\-]+)})+/', $uri, $matches);
|
|
||||||
$matches = $matches[1];
|
|
||||||
|
|
||||||
foreach ($matches as $match) {
|
|
||||||
$pattern = '{'.$match.'}';
|
|
||||||
|
|
||||||
if (in_array($match, $constraintKeys)) {
|
|
||||||
// Do some voodoo to allow users to use parentheses in their constraints if they want
|
|
||||||
$constraint = '('.rtrim(ltrim(trim($constraints[$match]), '('), ')').')';
|
|
||||||
|
|
||||||
$uri = str_replace($pattern, $constraint, $uri);
|
|
||||||
} else {
|
|
||||||
$uri = str_replace($pattern, self::$defaultConstraint, $uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the router. Accepts a base path from which to serve the routes, and optionally whether you want to try
|
|
||||||
* and match multiple routes.
|
|
||||||
*
|
|
||||||
* @param string $basePath
|
|
||||||
* @param boolean $multimatch
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function run(string $uri, string $basePath = '', bool $multimatch = false, string $method = ''): int|array
|
|
||||||
{
|
|
||||||
$basePath = self::trimRoute($basePath);
|
|
||||||
$path = urldecode(self::trimRoute($uri));
|
|
||||||
|
|
||||||
$pathMatchFound = false;
|
|
||||||
$routeMatchFound = false;
|
|
||||||
|
|
||||||
// Begin looking through routes
|
|
||||||
foreach (self::$routes as $route) {
|
|
||||||
// If the basePath isn't just "root"
|
|
||||||
if ($basePath != '/') {
|
|
||||||
$route['route'] = self::trimRoute($basePath.$route['route']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare route by tokenizing.
|
|
||||||
$tokenized = '#^'.self::tokenize($route['route'], $route['constraints']).'$#u';
|
|
||||||
|
|
||||||
// If the tokenized route matches the current path...
|
|
||||||
if (preg_match($tokenized, $path, $matches)) {
|
|
||||||
$pathMatchFound = true;
|
|
||||||
|
|
||||||
// Run through the route's accepted method(s)
|
|
||||||
foreach ((array) $route['methods'] as $allowedMethod) {
|
|
||||||
// See if the current request method matches
|
|
||||||
if (strtolower($method) == strtolower($allowedMethod)) {
|
|
||||||
array_shift($matches); // Remove the first match - always contains the full url
|
|
||||||
|
|
||||||
// If we're successful at calling the route's action, echo the result
|
|
||||||
return [$route['action'], $matches];
|
|
||||||
|
|
||||||
$routeMatchFound = true;
|
|
||||||
|
|
||||||
// Do not check other routes.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break the loop if the first found route is a match.
|
|
||||||
if($routeMatchFound && !$multimatch) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matching route was found
|
|
||||||
if (!$routeMatchFound) {
|
|
||||||
// But a matching path exists
|
|
||||||
if ($pathMatchFound) {
|
|
||||||
return 405;
|
|
||||||
} else {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function clearRoutes()
|
|
||||||
{
|
|
||||||
self::$routes = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class StaticRouter
|
|
||||||
{
|
|
||||||
public static function lookup(array $node, 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class TrieRouter implements Router
|
|
||||||
{
|
|
||||||
public array $root = [];
|
|
||||||
|
|
||||||
// Add route to the trie
|
|
||||||
public function add(string $method, string $route, callable $handler): Router
|
|
||||||
{
|
|
||||||
$node = &$this->root[$method];
|
|
||||||
// Expand the route into segments and make dynamic segments into a common placeholder
|
|
||||||
$segments = array_map(function($segment) {
|
|
||||||
return str_starts_with($segment, ':') ? ':x' : $segment;
|
|
||||||
}, explode('/', trim($route, '/')));
|
|
||||||
|
|
||||||
foreach ($segments as $segment) {
|
|
||||||
if (!isset($node[$segment])) {
|
|
||||||
$node[$segment] = ['_children' => [], '_handler' => null];
|
|
||||||
}
|
|
||||||
$node = &$node[$segment]['_children'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$node['_handler'] = $handler;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find and handle the route
|
|
||||||
public function lookup(string $method, string $uri): array
|
|
||||||
{
|
|
||||||
$node = &$this->root[$method];
|
|
||||||
$segments = explode('/', trim($uri, '/'));
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
foreach ($segments as $segment) {
|
|
||||||
if (isset($node[$segment])) {
|
|
||||||
$node = &$node[$segment]['_children'];
|
|
||||||
} else {
|
|
||||||
// Handle dynamic parameters (e.g., :id)
|
|
||||||
$dynamicSegment = $this->matchDynamicSegment($node, $segment);
|
|
||||||
if ($dynamicSegment) {
|
|
||||||
$params[] = $segment;
|
|
||||||
$node = &$node[$dynamicSegment]['_children'];
|
|
||||||
} else {
|
|
||||||
return ['code' => 404];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a handler exists for the current node
|
|
||||||
if (isset($node['_handler'])) return ['code' => 200, 'handler' => $node['_handler'], 'params' => $params];
|
|
||||||
|
|
||||||
return ['code' => 404];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match dynamic route segments like ':id'
|
|
||||||
private function matchDynamicSegment(array $node, string $segment)
|
|
||||||
{
|
|
||||||
foreach ($node as $key => $value) {
|
|
||||||
if (strpos($key, ':') === 0) return $key;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clear(): Router
|
|
||||||
{
|
|
||||||
$this->root = [];
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
19
composer.json
Normal file
19
composer.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "sharkk/router",
|
||||||
|
"description": "A simple node-based router.",
|
||||||
|
"type": "library",
|
||||||
|
"license": "MIT",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sharkk\\Router\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Sharkk",
|
||||||
|
"email": "email@sharkk.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"require": {}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class SegmentRouter implements Router
|
namespace Sharkk\Router;
|
||||||
|
|
||||||
|
class Router
|
||||||
{
|
{
|
||||||
public array $routes = [];
|
public array $routes = [];
|
||||||
|
|
64
tests/color.php
Normal file
64
tests/color.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Color {
|
||||||
|
const RESET = "\033[0m";
|
||||||
|
const BOLD = "\033[1m";
|
||||||
|
const UNDERLINE = "\033[4m";
|
||||||
|
const INVERSE = "\033[7m";
|
||||||
|
const BLACK = "\033[30m";
|
||||||
|
const RED = "\033[31m";
|
||||||
|
const GREEN = "\033[32m";
|
||||||
|
const YELLOW = "\033[33m";
|
||||||
|
const BLUE = "\033[34m";
|
||||||
|
const MAGENTA = "\033[35m";
|
||||||
|
const CYAN = "\033[36m";
|
||||||
|
const WHITE = "\033[37m";
|
||||||
|
|
||||||
|
private static function format(string $color, string $string): string {
|
||||||
|
return $color . $string . self::RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function bold(string $string): string {
|
||||||
|
return self::format(self::BOLD, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function underline(string $string): string {
|
||||||
|
return self::format(self::UNDERLINE, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function inverse(string $string): string {
|
||||||
|
return self::format(self::INVERSE, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function black(string $string): string {
|
||||||
|
return self::format(self::BLACK, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function red(string $string): string {
|
||||||
|
return self::format(self::RED, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function green(string $string): string {
|
||||||
|
return self::format(self::GREEN, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function yellow(string $string): string {
|
||||||
|
return self::format(self::YELLOW, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function blue(string $string): string {
|
||||||
|
return self::format(self::BLUE, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function magenta(string $string): string {
|
||||||
|
return self::format(self::MAGENTA, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cyan(string $string): string {
|
||||||
|
return self::format(self::CYAN, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function white(string $string): string {
|
||||||
|
return self::format(self::WHITE, $string);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ $midpoint = ['do', 'cause', 'effect', 'affect', 'impact', 'influence', 'change',
|
||||||
for ($i = 0; $i < 1000; $i++) {
|
for ($i = 0; $i < 1000; $i++) {
|
||||||
$routes[] = makeRoute();
|
$routes[] = makeRoute();
|
||||||
// write the routes array to a file
|
// write the routes array to a file
|
||||||
file_put_contents('big.txt', implode("\n", $routes));
|
file_put_contents('routes/big.txt', implode("\n", $routes));
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRoute(): string
|
function makeRoute(): string
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test file puts the SegmentRouter to the test by running a million lookups on a handful
|
|
||||||
of routes. The routes are read from two files, blog.txt and github.txt, and added to two separate
|
|
||||||
routers. The lookups are then run in two separate loops, one for each router.
|
|
||||||
Each lookup is timed and the memory usage is also printed out at regular intervals.
|
|
||||||
The requests are randomly picked from the array of routes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'tools.php';
|
|
||||||
|
|
||||||
$r = new SegmentRouter();
|
|
||||||
|
|
||||||
// Blog lookups
|
|
||||||
$blog = readAndAddRoutes('blog.txt', $r);
|
|
||||||
writeRoutesToFile($r->routes, 'storage/segment/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('github.txt', $r);
|
|
||||||
writeRoutesToFile($r->routes, 'storage/segment/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('big.txt', $r);
|
|
||||||
writeRoutesToFile($r->routes, 'storage/segment/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";
|
|
||||||
}],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($routes as $route) {
|
|
||||||
[$method, $path, $handler] = $route;
|
|
||||||
$r->add($method, $path, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
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']);
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test file puts the SimpleRouter to the test by running a million lookups on a handful
|
|
||||||
of routes. The routes are read from two files, blog.txt and github.txt, and added to two separate
|
|
||||||
routers and two separate arrays. The lookups are then run in two separate loops, one for each router.
|
|
||||||
Each lookup is timed and the memory usage is also printed out at regular intervals.
|
|
||||||
The requests are randomly picked from the array of routes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'tools.php';
|
|
||||||
require_once __DIR__ . '/../SimpleRouter.php';
|
|
||||||
|
|
||||||
// Blog test
|
|
||||||
$blog = sReadAndAddRoutes('blog.txt');
|
|
||||||
echoTitle("Starting blog lookups");
|
|
||||||
sRunIterations(100000, $blog);
|
|
||||||
sRunIterations(1000000, $blog);
|
|
||||||
|
|
||||||
// Github test
|
|
||||||
SimpleRouter::clearRoutes();
|
|
||||||
$github = sReadAndAddRoutes('github.txt');
|
|
||||||
echoTitle("Starting github lookups");
|
|
||||||
sRunIterations(10000, $github);
|
|
||||||
sRunIterations(100000, $github);
|
|
||||||
sRunIterations(1000000, $github);
|
|
||||||
|
|
||||||
// Big test; since simplerouter is so much slower, we'll only run the big test if the -b flag is passed
|
|
||||||
if (in_array('-b', $argv)) {
|
|
||||||
SimpleRouter::clearRoutes();
|
|
||||||
$big = sReadAndAddRoutes('big.txt');
|
|
||||||
echoTitle("Starting big lookups");
|
|
||||||
sRunIterations(10000, $big);
|
|
||||||
sRunIterations(100000, $big);
|
|
||||||
sRunIterations(1000000, $big);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sReadAndAddRoutes(string $file): array
|
|
||||||
{
|
|
||||||
$array = [];
|
|
||||||
$routes = file($file);
|
|
||||||
foreach ($routes as $route) {
|
|
||||||
[$method, $path] = explode(' ', $route);
|
|
||||||
$path = trim($path);
|
|
||||||
// convert params from :param to {param}
|
|
||||||
$path = preg_replace('/:(\w+)/', '{$1}', $path);
|
|
||||||
$array[] = [$method, $path];
|
|
||||||
SimpleRouter::add($path, function() {
|
|
||||||
return true;
|
|
||||||
}, $method);
|
|
||||||
}
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sRunIterations(int $iterations, array $routes) {
|
|
||||||
echo "Running $iterations iterations\n";
|
|
||||||
$start = microtime(true);
|
|
||||||
$interval = $iterations / 10;
|
|
||||||
for ($i = 0; $i < $iterations; $i++) {
|
|
||||||
// pick a random route from the array
|
|
||||||
[$method, $uri] = $routes[array_rand($routes)];
|
|
||||||
// replace the params with random values
|
|
||||||
$uri = preg_replace_callback('/{(\w+)}/', function($matches) {
|
|
||||||
return $matches[1] . '-' . rand(1, 100);
|
|
||||||
}, $uri);
|
|
||||||
$res = SimpleRouter::run($uri, '', false, $method);
|
|
||||||
if ($res === 404 || $res === 405) {
|
|
||||||
echo Color::red("Failed to handle request for $uri - $res\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if ($i !== 0 && $i % ($interval) === 0) echoMemoryAndTime($i, $start);
|
|
||||||
}
|
|
||||||
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((microtime(true) - $start) / $iterations, 10) . " s\n");
|
|
||||||
echo "\n";
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
<?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;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +0,0 @@
|
||||||
/
|
|
||||||
├── GET
|
|
||||||
├── :x
|
|
||||||
│ └── GET
|
|
||||||
├── tags
|
|
||||||
│ └── GET
|
|
||||||
└── tag
|
|
||||||
└── :x
|
|
||||||
└── GET
|
|
|
@ -1,376 +0,0 @@
|
||||||
/
|
|
||||||
├── authorizations
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── POST
|
|
||||||
├── applications
|
|
||||||
│ └── :x
|
|
||||||
│ └── tokens
|
|
||||||
│ ├── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── DELETE
|
|
||||||
├── events
|
|
||||||
│ └── GET
|
|
||||||
├── repos
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ ├── events
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── notifications
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── PUT
|
|
||||||
│ ├── stargazers
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── subscribers
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── subscription
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── git
|
|
||||||
│ │ ├── blobs
|
|
||||||
│ │ │ ├── :x
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ └── POST
|
|
||||||
│ │ ├── commits
|
|
||||||
│ │ │ ├── :x
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ └── POST
|
|
||||||
│ │ ├── refs
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── POST
|
|
||||||
│ │ ├── tags
|
|
||||||
│ │ │ ├── :x
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ └── POST
|
|
||||||
│ │ └── trees
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── issues
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── comments
|
|
||||||
│ │ │ │ ├── GET
|
|
||||||
│ │ │ │ └── POST
|
|
||||||
│ │ │ ├── events
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ └── labels
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── POST
|
|
||||||
│ │ │ ├── :x
|
|
||||||
│ │ │ │ └── DELETE
|
|
||||||
│ │ │ ├── PUT
|
|
||||||
│ │ │ └── DELETE
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── assignees
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── labels
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── DELETE
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── milestones
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── labels
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── DELETE
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── pulls
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── commits
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ ├── files
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ ├── merge
|
|
||||||
│ │ │ │ ├── GET
|
|
||||||
│ │ │ │ └── PUT
|
|
||||||
│ │ │ └── comments
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── PUT
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── contributors
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── languages
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── teams
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── tags
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── branches
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── DELETE
|
|
||||||
│ ├── collaborators
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── comments
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── commits
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── comments
|
|
||||||
│ │ │ │ ├── GET
|
|
||||||
│ │ │ │ └── POST
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── readme
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── keys
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── DELETE
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── downloads
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── forks
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── hooks
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── tests
|
|
||||||
│ │ │ │ └── POST
|
|
||||||
│ │ │ └── DELETE
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── merges
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── releases
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── :x
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── DELETE
|
|
||||||
│ │ │ └── assets
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── stats
|
|
||||||
│ │ ├── contributors
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── commit_activity
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── code_frequency
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── participation
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ └── punch_card
|
|
||||||
│ │ └── GET
|
|
||||||
│ └── statuses
|
|
||||||
│ └── :x
|
|
||||||
│ ├── GET
|
|
||||||
│ └── POST
|
|
||||||
├── networks
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ └── events
|
|
||||||
│ └── GET
|
|
||||||
├── orgs
|
|
||||||
│ └── :x
|
|
||||||
│ ├── events
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── issues
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── members
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── public_members
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── teams
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ └── repos
|
|
||||||
│ ├── GET
|
|
||||||
│ └── POST
|
|
||||||
├── users
|
|
||||||
│ ├── :x
|
|
||||||
│ │ ├── received_events
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── public
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── events
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ ├── public
|
|
||||||
│ │ │ │ └── GET
|
|
||||||
│ │ │ └── orgs
|
|
||||||
│ │ │ └── :x
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── starred
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── subscriptions
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── gists
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── orgs
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── repos
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── followers
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── following
|
|
||||||
│ │ │ ├── GET
|
|
||||||
│ │ │ └── :x
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ └── keys
|
|
||||||
│ │ └── GET
|
|
||||||
│ └── GET
|
|
||||||
├── feeds
|
|
||||||
│ └── GET
|
|
||||||
├── notifications
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── PUT
|
|
||||||
│ └── threads
|
|
||||||
│ └── :x
|
|
||||||
│ ├── GET
|
|
||||||
│ └── subscription
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── PUT
|
|
||||||
│ └── DELETE
|
|
||||||
├── user
|
|
||||||
│ ├── starred
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── subscriptions
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── issues
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── orgs
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── teams
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── repos
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── POST
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── emails
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── POST
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ ├── followers
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── following
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── keys
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── POST
|
|
||||||
├── gists
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── star
|
|
||||||
│ │ │ ├── PUT
|
|
||||||
│ │ │ ├── DELETE
|
|
||||||
│ │ │ └── GET
|
|
||||||
│ │ ├── forks
|
|
||||||
│ │ │ └── POST
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── POST
|
|
||||||
├── issues
|
|
||||||
│ └── GET
|
|
||||||
├── emojis
|
|
||||||
│ └── GET
|
|
||||||
├── gitignore
|
|
||||||
│ └── templates
|
|
||||||
│ ├── GET
|
|
||||||
│ └── :x
|
|
||||||
│ └── GET
|
|
||||||
├── markdown
|
|
||||||
│ ├── POST
|
|
||||||
│ └── raw
|
|
||||||
│ └── POST
|
|
||||||
├── meta
|
|
||||||
│ └── GET
|
|
||||||
├── rate_limit
|
|
||||||
│ └── GET
|
|
||||||
├── teams
|
|
||||||
│ └── :x
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── DELETE
|
|
||||||
│ ├── members
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ └── :x
|
|
||||||
│ │ ├── GET
|
|
||||||
│ │ ├── PUT
|
|
||||||
│ │ └── DELETE
|
|
||||||
│ └── repos
|
|
||||||
│ ├── GET
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ ├── GET
|
|
||||||
│ ├── PUT
|
|
||||||
│ └── DELETE
|
|
||||||
├── repositories
|
|
||||||
│ └── GET
|
|
||||||
├── search
|
|
||||||
│ ├── repositories
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── code
|
|
||||||
│ │ └── GET
|
|
||||||
│ ├── issues
|
|
||||||
│ │ └── GET
|
|
||||||
│ └── users
|
|
||||||
│ └── GET
|
|
||||||
└── legacy
|
|
||||||
├── issues
|
|
||||||
│ └── search
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ └── :x
|
|
||||||
│ └── GET
|
|
||||||
├── repos
|
|
||||||
│ └── search
|
|
||||||
│ └── :x
|
|
||||||
│ └── GET
|
|
||||||
└── user
|
|
||||||
├── search
|
|
||||||
│ └── :x
|
|
||||||
│ └── GET
|
|
||||||
└── email
|
|
||||||
└── :x
|
|
||||||
└── GET
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
||||||
/
|
|
||||||
└── GET
|
|
||||||
├── /
|
|
||||||
│ ├── _children
|
|
||||||
│ │ └── _handler
|
|
||||||
│ └── _handler
|
|
||||||
├── :x
|
|
||||||
│ ├── _children
|
|
||||||
│ │ └── _handler
|
|
||||||
│ └── _handler
|
|
||||||
├── tags
|
|
||||||
│ ├── _children
|
|
||||||
│ │ └── _handler
|
|
||||||
│ └── _handler
|
|
||||||
└── tag
|
|
||||||
├── _children
|
|
||||||
│ └── :x
|
|
||||||
│ ├── _children
|
|
||||||
│ │ └── _handler
|
|
||||||
│ └── _handler
|
|
||||||
└── _handler
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,84 +1,86 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'color.php';
|
||||||
|
require_once __DIR__ . '/../src/Router.php';
|
||||||
|
|
||||||
|
use Sharkk\Router\Router;
|
||||||
|
|
||||||
// if there's a flag, reset the opcache
|
// if there's a flag, reset the opcache
|
||||||
if (in_array('-f', $argv)) {
|
if (in_array('-f', $argv)) {
|
||||||
opcache_reset();
|
opcache_reset();
|
||||||
echoTitle("opcache reset");
|
echoTitle("opcache reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/../Router.php';
|
$r = new Router();
|
||||||
require_once __DIR__ . '/../SegmentRouter.php';
|
|
||||||
require_once __DIR__ . '/../TrieRouter.php';
|
|
||||||
|
|
||||||
// A simple class to return a string wrapped in ANSI color codes for terminal output
|
// Blog lookups
|
||||||
class Color {
|
$blog = readAndAddRoutes('routes/blog.txt', $r);
|
||||||
const RESET = "\033[0m";
|
writeRoutesToFile($r->routes, 'trees/blog.txt');
|
||||||
const BOLD = "\033[1m";
|
echoTitle("Starting blog lookups");
|
||||||
const UNDERLINE = "\033[4m";
|
runIterations(10000, $r, $blog);
|
||||||
const INVERSE = "\033[7m";
|
runIterations(100000, $r, $blog);
|
||||||
const BLACK = "\033[30m";
|
runIterations(1000000, $r, $blog);
|
||||||
const RED = "\033[31m";
|
unset($blog);
|
||||||
const GREEN = "\033[32m";
|
|
||||||
const YELLOW = "\033[33m";
|
|
||||||
const BLUE = "\033[34m";
|
|
||||||
const MAGENTA = "\033[35m";
|
|
||||||
const CYAN = "\033[36m";
|
|
||||||
const WHITE = "\033[37m";
|
|
||||||
|
|
||||||
private static function format(string $color, string $string): string {
|
// Github lookups
|
||||||
return $color . $string . self::RESET;
|
$r->clear();
|
||||||
}
|
$github = readAndAddRoutes('routes/github.txt', $r);
|
||||||
|
writeRoutesToFile($r->routes, 'trees/github.txt');
|
||||||
|
echoTitle("Starting github lookups");
|
||||||
|
runIterations(10000, $r, $github);
|
||||||
|
runIterations(100000, $r, $github);
|
||||||
|
runIterations(1000000, $r, $github);
|
||||||
|
unset($github);
|
||||||
|
|
||||||
public static function bold(string $string): string {
|
// Big lookups
|
||||||
return self::format(self::BOLD, $string);
|
$r->clear();
|
||||||
}
|
$big = readAndAddRoutes('routes/big.txt', $r);
|
||||||
|
writeRoutesToFile($r->routes, 'trees/big.txt');
|
||||||
|
echoTitle("Starting big lookups");
|
||||||
|
runIterations(10000, $r, $big);
|
||||||
|
runIterations(100000, $r, $big);
|
||||||
|
runIterations(1000000, $r, $big);
|
||||||
|
unset($big);
|
||||||
|
|
||||||
public static function underline(string $string): string {
|
// Parameter testing
|
||||||
return self::format(self::UNDERLINE, $string);
|
$r->clear();
|
||||||
}
|
echoTitle("Testing parameters");
|
||||||
|
|
||||||
public static function inverse(string $string): string {
|
$routes = [
|
||||||
return self::format(self::INVERSE, $string);
|
['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";
|
||||||
|
}],
|
||||||
|
];
|
||||||
|
|
||||||
public static function black(string $string): string {
|
foreach ($routes as $route) {
|
||||||
return self::format(self::BLACK, $string);
|
[$method, $path, $handler] = $route;
|
||||||
}
|
$r->add($method, $path, $handler);
|
||||||
|
|
||||||
public static function red(string $string): string {
|
|
||||||
return self::format(self::RED, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function green(string $string): string {
|
|
||||||
return self::format(self::GREEN, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function yellow(string $string): string {
|
|
||||||
return self::format(self::YELLOW, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function blue(string $string): string {
|
|
||||||
return self::format(self::BLUE, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function magenta(string $string): string {
|
|
||||||
return self::format(self::MAGENTA, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function cyan(string $string): string {
|
|
||||||
return self::format(self::CYAN, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function white(string $string): string {
|
|
||||||
return self::format(self::WHITE, $string);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function echoMemoryAndTime(int $i, float $start) {
|
for ($i = 0; $i < 10; $i++) {
|
||||||
echo "(".Color::green("$i lookups").") M: " .
|
[$method, $uri] = $routes[array_rand($routes)];
|
||||||
Color::blue(round(memory_get_usage() / 1024, 1) . " kb") .
|
|
||||||
" - T: ". Color::blue(number_format(microtime(true) - $start, 10) ." s") .
|
// Generate some random parameters
|
||||||
"\n";
|
$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']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function echoTitle(string $title) {
|
function echoTitle(string $title) {
|
||||||
|
@ -207,4 +209,3 @@ function writeNode($node, $indent, $prefix, $fp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test file puts the PATRICIA trie to the test by running a million lookups on a handful
|
|
||||||
of routes. The routes are read from two files, blog.txt and github.txt, and added to two separate
|
|
||||||
routers and two separate arrays. The lookups are then run in two separate loops, one for each router.
|
|
||||||
Each lookup is timed and the memory usage is also printed out at regular intervals.
|
|
||||||
The requests are randomly picked from the array of routes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'tools.php';
|
|
||||||
|
|
||||||
$r = new TrieRouter();
|
|
||||||
|
|
||||||
// Blog test
|
|
||||||
$blog = readAndAddRoutes('blog.txt', $r);
|
|
||||||
writeRoutesToFile($r->root, 'storage/trie/blog.txt');
|
|
||||||
echoTitle("Starting blog lookups");
|
|
||||||
runIterations(100000, $r, $blog);
|
|
||||||
runIterations(1000000, $r, $blog);
|
|
||||||
|
|
||||||
// Github test
|
|
||||||
$r->clear();
|
|
||||||
$github = readAndAddRoutes('github.txt', $r);
|
|
||||||
writeRoutesToFile($r->root, 'storage/trie/github.txt');
|
|
||||||
echoTitle("Starting github lookups");
|
|
||||||
runIterations(10000, $r, $github);
|
|
||||||
runIterations(100000, $r, $github);
|
|
||||||
runIterations(1000000, $r, $github);
|
|
||||||
|
|
||||||
// Big test
|
|
||||||
$r->clear();
|
|
||||||
$big = readAndAddRoutes('big.txt', $r);
|
|
||||||
writeRoutesToFile($r->root, 'storage/trie/big.txt');
|
|
||||||
echoTitle("Starting big lookups");
|
|
||||||
runIterations(10000, $r, $big);
|
|
||||||
runIterations(100000, $r, $big);
|
|
||||||
runIterations(1000000, $r, $big);
|
|
Loading…
Reference in New Issue
Block a user