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.
- 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
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.
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.
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.
- 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.
composer install
composer testThe test matrix covers PHP 8.3–8.5. See the release notes and performance measurements.
MIT License. See LICENSE.