mirror of
https://github.com/dannyvankooten/AltoRouter.git
synced 2025-08-23 16:42:48 +02:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
127f6e9699 | ||
|
a80bb36f11 | ||
|
a51c74793a |
@@ -204,6 +204,8 @@ class AltoRouter
|
||||
$requestUrl = substr($requestUrl, 0, $strpos);
|
||||
}
|
||||
|
||||
$lastRequestUrlChar = $requestUrl[strlen($requestUrl)-1];
|
||||
|
||||
// set Request Method if it isn't passed as a parameter
|
||||
if ($requestMethod === null) {
|
||||
$requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
|
||||
@@ -230,10 +232,12 @@ class AltoRouter
|
||||
// No params in url, do string comparison
|
||||
$match = strcmp($requestUrl, $route) === 0;
|
||||
} else {
|
||||
// Compare longest non-param string with url
|
||||
if (strncmp($requestUrl, $route, $position) !== 0) {
|
||||
// Compare longest non-param string with url before moving on to regex
|
||||
// Check if last character before param is a slash, because it could be optional if param is optional too (see https://github.com/dannyvankooten/AltoRouter/issues/241)
|
||||
if (strncmp($requestUrl, $route, $position) !== 0 && ($lastRequestUrlChar === '/' || $route[$position-1] !== '/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$regex = $this->compileRoute($route);
|
||||
$match = preg_match($regex, $requestUrl, $params) === 1;
|
||||
}
|
||||
@@ -254,6 +258,7 @@ class AltoRouter
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -142,10 +142,10 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
*/
|
||||
public function testSetBasePath()
|
||||
{
|
||||
$basePath = $this->router->setBasePath('/some/path');
|
||||
$this->router->setBasePath('/some/path');
|
||||
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||
|
||||
$basePath = $this->router->setBasePath('/some/path');
|
||||
$this->router->setBasePath('/some/path');
|
||||
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
->getMock();
|
||||
|
||||
// this should prove that compileRoute is not called when the route doesn't
|
||||
// have any params in it, but this doesn't work because compileRoute is private.
|
||||
// have any params in it
|
||||
$router->expects($this->never())
|
||||
->method('compileRoute');
|
||||
|
||||
@@ -384,8 +384,6 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'name' => 'contact'
|
||||
], $router->match('/contact', 'GET'));
|
||||
|
||||
$router->map('GET', '/page/[:id]', 'pages#show', 'page');
|
||||
|
||||
// no prefix match, so no regex compilation necessary
|
||||
$this->assertFalse($router->match('/page1', 'GET'));
|
||||
}
|
||||
@@ -519,6 +517,20 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$this->assertFalse($this->router->match('/﷽', 'GET'));
|
||||
}
|
||||
|
||||
public function testMatchWithSlashBeforeOptionalPart()
|
||||
{
|
||||
$this->router->map('GET', '/archives/[lmin:category]?', 'Article#archives');
|
||||
$expected = [
|
||||
'target' => 'Article#archives',
|
||||
'params' => [],
|
||||
'name' => null
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $this->router->match('/archives/', 'GET'));
|
||||
$this->assertEquals($expected, $this->router->match('/archives', 'GET'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AltoRouter::addMatchTypes
|
||||
*/
|
||||
|
106
tests/benchmark-parse-api.php
Normal file
106
tests/benchmark-parse-api.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Benchmark Altorouter
|
||||
*
|
||||
* Usage: php ./tests/benchmark-parse-api.php <iterations>
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* <iterations>:
|
||||
* The number of routes to map & match. Defaults to 1000.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
$routes = [
|
||||
["POST", "/1/classes/[a:className]"],
|
||||
["GET", "/1/classes/[a:className]/[i:objectId]"],
|
||||
["PUT", "/1/classes/[a:className]/[i:objectId]"],
|
||||
["GET", "/1/classes/[a:className]"],
|
||||
["DELETE", "/1/classes/[a:className]/[i:objectId]"],
|
||||
|
||||
// Users
|
||||
["POST", "/1/users"],
|
||||
["GET", "/1/login"],
|
||||
["GET", "/1/users/[i:objectId]"],
|
||||
["PUT", "/1/users/[i:objectId]"],
|
||||
["GET", "/1/users"],
|
||||
["DELETE", "/1/users/[i:objectId]"],
|
||||
["POST", "/1/requestPasswordReset"],
|
||||
|
||||
// Roles
|
||||
["POST", "/1/roles"],
|
||||
["GET", "/1/roles/[i:objectId]"],
|
||||
["PUT", "/1/roles/[i:objectId]"],
|
||||
["GET", "/1/roles"],
|
||||
["DELETE", "/1/roles/[i:objectId]"],
|
||||
|
||||
// Files
|
||||
["POST", "/1/files/:fileName"],
|
||||
|
||||
// Analytics
|
||||
["POST", "/1/events/[a:eventName]"],
|
||||
|
||||
// Push Notifications
|
||||
["POST", "/1/push"],
|
||||
|
||||
// Installations
|
||||
["POST", "/1/installations"],
|
||||
["GET", "/1/installations/[i:objectId]"],
|
||||
["PUT", "/1/installations/[i:objectId]"],
|
||||
["GET", "/1/installations"],
|
||||
["DELETE", "/1/installations/[i:objectId]"],
|
||||
|
||||
// Cloud Functions
|
||||
["POST", "/1/functions"],
|
||||
];
|
||||
$total_time = 0;
|
||||
$router = new AltoRouter();
|
||||
|
||||
// map requests
|
||||
$start = microtime(true);
|
||||
foreach ($routes as $r) {
|
||||
$router->map($r[0], $r[1], '');
|
||||
}
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Map time: %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a static route
|
||||
$start = microtime(true);
|
||||
$router->match('/1/login', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, no params): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a route with 1 parameter
|
||||
$start = microtime(true);
|
||||
$res = $router->match('/1/classes/foo', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, 1 param): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a route with 2 parameters
|
||||
$start = microtime(true);
|
||||
$res = $router->match('/1/classes/foo/500', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, 2 params): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
|
||||
// match unexisting route
|
||||
$start = microtime(true);
|
||||
$router->match('/55-foo-bar', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (unexisting route): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// print totals
|
||||
echo sprintf('Total time: %.3f ms', $total_time * 1000) . PHP_EOL;
|
||||
echo sprintf('Memory usage: %d KB', round(memory_get_usage() / 1024)) . PHP_EOL;
|
||||
echo sprintf('Peak memory usage: %d KB', round(memory_get_peak_usage(true) / 1024)) . PHP_EOL;
|
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Benchmark Altorouter
|
||||
*
|
||||
* Usage: php ./tests/benchmark.php <iterations>
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* <iterations>:
|
||||
* The number of routes to map & match. Defaults to 1000.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
global $argv;
|
||||
$n = isset($argv[1]) ? intval($argv[1]) : 1000;
|
||||
|
||||
// generates a random request url
|
||||
function random_request_url()
|
||||
{
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '/';
|
||||
|
||||
// create random path of 5-20 characters
|
||||
for ($i = 0; $i < rand(5, 20); $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
|
||||
if (rand(1, 10) === 1) {
|
||||
$randomString .= '/';
|
||||
}
|
||||
}
|
||||
|
||||
// add dynamic route with 10% chance
|
||||
if (rand(1, 10) === 1) {
|
||||
$randomString = rtrim($randomString, '/') . '/[:part]';
|
||||
}
|
||||
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
// generate a random request method
|
||||
function random_request_method()
|
||||
{
|
||||
static $methods = [ 'GET', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE' ];
|
||||
$random_key = array_rand($methods);
|
||||
return $methods[ $random_key ];
|
||||
}
|
||||
|
||||
// prepare benchmark data
|
||||
$requests = [];
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$requests[] = [
|
||||
'method' => random_request_method(),
|
||||
'url' => random_request_url(),
|
||||
];
|
||||
}
|
||||
|
||||
$router = new AltoRouter();
|
||||
|
||||
// map requests
|
||||
$start = microtime(true);
|
||||
foreach ($requests as $r) {
|
||||
$router->map($r['method'], $r['url'], '');
|
||||
}
|
||||
$end = microtime(true);
|
||||
$map_time = ($end - $start) * 1000;
|
||||
echo sprintf('Map time: %.2f ms', $map_time) . PHP_EOL;
|
||||
|
||||
|
||||
// pick random route to match
|
||||
$r = $requests[array_rand($requests)];
|
||||
|
||||
// match random known route
|
||||
$start = microtime(true);
|
||||
$router->match($r['url'], $r['method']);
|
||||
$end = microtime(true);
|
||||
$match_time_known_route = ($end - $start) * 1000;
|
||||
echo sprintf('Match time (known route): %.2f ms', $match_time_known_route) . PHP_EOL;
|
||||
|
||||
// match unexisting route
|
||||
$start = microtime(true);
|
||||
$router->match('/55-foo-bar', 'GET');
|
||||
$end = microtime(true);
|
||||
$match_time_unknown_route = ($end - $start) * 1000;
|
||||
echo sprintf('Match time (unknown route): %.2f ms', $match_time_unknown_route) . PHP_EOL;
|
||||
|
||||
// print totals
|
||||
echo sprintf('Total time: %.2f seconds', ($map_time + $match_time_known_route + $match_time_unknown_route)) . PHP_EOL;
|
||||
echo sprintf('Memory usage: %d KB', round(memory_get_usage() / 1024)) . PHP_EOL;
|
||||
echo sprintf('Peak memory usage: %d KB', round(memory_get_peak_usage(true) / 1024)) . PHP_EOL;
|
Reference in New Issue
Block a user