azjezz / hack-routing
Fast, type-safe request routing, parameter retrieval, and link generation.
Installs: 1 123
Dependents: 1
Suggesters: 0
Security: 0
Stars: 26
Watchers: 4
Forks: 0
Open Issues: 1
pkg:composer/azjezz/hack-routing
Requires
- php: ^8.0
- azjezz/psl: ^1.7.2
Requires (Dev)
- ext-apcu: *
- php-standard-library/psalm-plugin: ^1.1.1
- phpunit/phpunit: ^9.5.5
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.6.0
- vimeo/psalm: ^4.7.3
This package is auto-updated.
Last update: 2025-10-11 04:10:02 UTC
README
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.