lizzyman04 / file-router
Next.js-style file-based routing for PHP. Zero dependencies, framework-agnostic.
v1.0.0
2026-06-18 16:31 UTC
Requires
- php: ^8.1
Requires (Dev)
- phpunit/phpunit: ^10.0
README
Next.js-style file-based routing for PHP. The directory structure is the route table — no separate route file to keep in sync. Zero runtime dependencies, framework-agnostic, PHP 8.1+.
Extracted from Fluxor so it can be used standalone or dropped into any stack.
Install
composer require lizzyman04/file-router
Routing conventions
| File on disk | URL pattern | Params |
|---|---|---|
index.php |
/ |
— |
about.php |
/about |
— |
users/[id].php |
/users/{id} |
id |
posts/[id]/comments.php |
/posts/{id}/comments |
id |
files/[...slug].php |
/files/{slug:*} (catch-all) |
slug (rest of path) |
(admin)/dashboard.php |
/dashboard |
group folder stripped |
Matching is specificity-ordered: static > dynamic > catch-all, so
/users/me beats /users/[id].
Standalone usage
use FileRouter\FileRouter; $router = new FileRouter(__DIR__ . '/routes'); $match = $router->match($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']); if ($match === null) { http_response_code(404); } elseif ($match->isMethodNotAllowed()) { http_response_code(405); header('Allow: ' . implode(', ', $match->allowedMethods)); } else { // $match->file — the route file to include/dispatch // $match->params — e.g. ['id' => '42'] for /users/42 (function (string $__file, array $params) { include $__file; })($match->file, $match->params); }
PSR-7
match() takes a method and a path string, so any PSR-7 request adapts in one line:
$match = $router->match( $request->getMethod(), $request->getUri()->getPath() );
Options
$router = new FileRouter(__DIR__ . '/routes', [ // Where compiled routes are cached. Omit for no caching (compile per request). 'cacheDir' => __DIR__ . '/var/cache', 'cache' => true, // How route files declare their HTTP methods. Default: Flow syntax. 'methodExtractor' => new \FileRouter\Extractor\FlowMethodExtractor(), ]); $router->clearCache(); // invalidate the compiled table
Method extractors
A route file can serve several HTTP methods; how that's declared is pluggable
via the MethodExtractor interface.
FlowMethodExtractor(default) — readsFlow::GET(),Flow::POST(), … declarations (Fluxor style).Flow::ANY()expands to all methods. No dependency on Fluxor; it only reads the file's text.FixedMethodExtractor— every route file serves the same fixed set of methods (e.g. you dispatch by method inside the file).- Custom — implement
MethodExtractor::extract(string $file): array.
Framework adapters
Testing
composer test
License
MIT