solophp / router
PHP router with an independent route builder, immutable runtime, typed results, and compiled matching.
Requires
- php: ^8.3
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^12.0
- squizlabs/php_codesniffer: ^3.9
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
PHP router with a fluent route builder, immutable runtime routes, middleware metadata, groups, and advanced optional segment patterns.
Upgrading from v3? Read the migration guide. Version 4 introduces a separate builder and immutable runtime.
Features
- Separate builder and runtime — Configure a
RouteCollector, thenbuild()an immutableRoutersnapshot - Typed results —
resolve()returnsMatched,NotFound, orMethodNotAllowed - Compiled matching — Static routes use hash lookup; the dynamic routes of each method compile into one regex shaped as an order-preserving prefix tree
- Fluent definitions — Chain
name(),middleware(), andattribute()before building - URL generation —
UrlGeneratorbuilds the path of a named route, with encoded values checked against their patterns - Groups — Nested prefixes, middleware, and attributes
- Advanced patterns — Optional segments anywhere, nested optionals, and regex constraints
- Route cache —
RouteCachekeeps a built router in a PHP file that OPcache serves in under 2 µs per request, without registering or building routes - Build-time validation — Duplicate names/paths, routes that could never match, invalid syntax, and invalid regexes fail at
build() - HEAD and 405 support — HEAD falls back to GET; method failures include allowed methods
Installation
composer require "solophp/router:^4.0"
Requires PHP 8.3 or later in the PHP 8 series and Composer. No runtime package dependencies. See installation for setup and integration changes.
Quick Example
require __DIR__ . '/vendor/autoload.php'; use Solo\Router\RouteCollector; use Solo\Router\Results\Matched; use Solo\Router\Results\MethodNotAllowed; use Solo\Router\UrlGenerator; $routes = new RouteCollector(); $routes->get('/users', [UserController::class, 'index']); $routes->get('/users/{id}', [UserController::class, 'show']) ->name('users.show'); $routes->post('/posts', [PostController::class, 'store']) ->middleware(AuthMiddleware::class) ->name('posts.store') ->attribute('permission', 'posts.create'); $routes->group('/admin', function (RouteCollector $routes) { $routes->get('/dashboard', [AdminController::class, 'dashboard']); }, [AuthMiddleware::class], ['permission' => 'admin']); $router = $routes->build(); $result = $router->resolve('GET', '/users/123'); if ($result instanceof Matched) { $handler = $result->route->handler; $params = $result->params; // ['id' => '123'] $middlewares = $result->route->middlewares; $name = $result->route->name; $attributes = $result->route->attributes; // Dispatch the handler and middleware in your application. } elseif ($result instanceof MethodNotAllowed) { http_response_code(405); header('Allow: ' . implode(', ', $result->allowedMethods)); } else { http_response_code(404); } $urls = new UrlGenerator($router); $urls->generate('users.show', ['id' => 123]); // '/users/123'
Changing a definition after build() affects subsequent builds only. Runtime routes have readonly properties. Handlers and object-valued attributes remain application-owned objects; the router does not deep-clone them.
Performance
Microseconds per lookup in a table of 1,000 GET routes, with PHP 8.4 and OPcache on one machine. A dash means the library does not support that layout or request with the measured API.
| Layout and request | Solo Router 4 | Leaf 5 | Symfony compiled | Slim 4 (FastRoute) |
|---|---|---|---|---|
/resourceN/{id}, match |
0.43 | 0.54 | 0.57 | 2.07 |
/resourceN/{id}, 404 |
0.31 | 0.33 | 0.67 | 7.53 |
/resourceN/{id}, 405 |
0.44 | — | 4.39 | 2.28 |
/{lang:[a-z]{2}}/resourceN/{id}, match |
0.53 | — | 0.73 | 7.61 |
Building 1,000 routes takes 1.2–2.8 ms; RouteCache loads a built router in under 2 µs. See the methodology and all layouts.
Documentation
- Quick start
- Migrating from v3
- Handlers
- Route parameters
- Optional segments
- Groups
- Middleware
- Named routes
- URL generation
- Attributes
- Route cache
- Builder API
- Runtime API
- Route and definition API
- Route cache API
- URL generator API
The package requires only PHP. Route matching, URL generation, metadata, compilation, and route caching are its scope; applications handle dispatch.
Development
composer install
composer test
The test matrix covers PHP 8.3–8.5. See the release notes and performance measurements.
License
MIT License. See LICENSE.