Hack-Routing
Fast, type-safe request routing, parameter retrieval, and link generation.
It's a port of hack-router By Facebook, Inc.
Components
HTTP Exceptions
Exception classes representing common situations in HTTP applications:
HackRouting\HttpException\InternalServerErrorExceptionHackRouting\HttpException\MethodNotAllowedExceptionHackRouting\HttpException\NotFoundException
Router
A simple typed request router. Example:
<?php
use Psl\Str;
use HackRouting\Cache;
use HackRouting\Router;
use HackRouting\HttpMethod;
use HackRouting\HttpException;
$cache = new Cache\ApcuCache();
$router = new Router($cache);
$router->addRoute(HttpMethod::GET, '/', function (): string {
return 'Hello, World!';
});
$router->addRoute(HttpMethod::GET, '/user/{username:[a-z]+}', function (array $parameters): string {
return Str\format('Hello, %s!', $parameters['username']);
});
$router->addRoute(HttpMethod::POST, '/', function (): string {
return 'Hello, POST world';
});
$router->addRoute(HttpMethod::GET, '/{page:about|contact}-us', static function (array $parameters): string {
if ($parameters['page'] === 'about') {
return 'Learn about us';
}
return 'Contact us';
});
try {
[$responder, $parameters] = $router->match('GET', '/user/azjezz');
$responder($parameters); // Hello, azjezz!
} catch (HttpException\MethodNotAllowedException $e) {
$allowed_methods = $e->getAllowedMethods();
// Handle 405.
} catch (HttpException\NotFoundException) {
// Handle 404.
} catch (HttpException\InternalServerErrorException) {
// Handle 500.
}
AbstractRouter
A more low-level router, which allows you to load routes using other means ( e.g. from configuration files ).
<?php
use Psl\Str;
use HackRouting\AbstractRouter;
use HackRouting\HttpMethod;
/**
* @extends BaseRouter<(function(array<string, string>):string)>
*/
final class Matcher extends AbstractRouter {
/**
* @return array<non-empty-string, array<string, (function(array<string, string>):string)>>
*/
protected function getRoutes(): array {
return [
HttpMethod::GET => [
'/' => static fn(array $parameters): string => 'Hello, World!',
'/user/{username}/' => static fn(array $parameters): string => Str\format('Hello, %s!', $parameters['username']),
],
HttpMethod::POST => [
'/' => static fn(array $parameters): string => 'Hello, POST world',
],
];
}
}
Simplified for conciseness - see examples/AbstractRouterExample.php for full executable example.
UriPatterns
Generate route fragments, URIs (for linking), and retrieve URI parameters in a consistent and type-safe way:
<?php
use HackRouting\UriPattern\UriPattern;
final class UserPageController extends WebController {
public static function getUriPattern(): UriPattern {
return (new UriPattern())
->literal('/users/')
->string('user_name');
}
// ...
}
Parameters can be retrieved, with types checked at runtime both against the values, and the definition:
public function getResponse(): string {
return 'Hello, '.$this->getUriParameters()->getString('user_name');
}
You can also generate links to controllers:
$link = UserPageController::getUriBuilder()
->setString('user_name', 'Mr Hankey')
->getPath();
These examples are simplified for conciseness - see examples/UriPatternsExample.php for full executable example.
Caching
HackRouting comes with 4 caching strategies.
HackRouting\Cache\ApcuCacheHackRouting\Cache\FileCacheHackRouting\Cache\MemoryCacheHackRouting\Cache\NullCache
By default, the router will use NullCache strategy, however, in production, it's extremely recommended using another strategy that fits your need.
If your application is running behind a traditional web-server ( i.e: fpm/fast-cgi ), we recommend using ApcuCache strategy if possible, falling back to FileCache.
If your application is used with a long-running process server such as Amphp, ReactPHP, RoadRunner ... etc, it's recommended to use MemoryCache to avoid additional I/O operations, and maximize performance.
Contributing
We welcome GitHub issues and pull requests - please see CONTRIBUTING.md for details.
License
hack-routing is MIT-licensed.