For one of the courses I teach I was in need of a PHP Router. Having explored the available routers out there I found they either were:
- Outdated
- Not object oriented
(sorry Klein (which has been updated by now, but wasn’t at the time)) - Rather bad at the separation of concerns
(sorry Ham & Klein; a router should only route, not handle templates/logging/sessions/…) - Not powerful enough
(sorry JREAM/route; there’s more than justGET
you know) - To be part of a bigger framework
(sorry Silex and Slim) - Bloated for a one-time lab/to get things quickly up and running
(sorry Symfony Routing) - …
In the end I decided to write one myself which I’ve polised for publication over the past few days. The result is bramus/router
, a lightweight and simple object oriented PHP Router. A typical implementation of the class is this:
// Require composer autoloader
require __DIR__ . '/vendor/autoload.php';
// Create a Router
$router = new \Bramus\Router\Router();
// Custom 404 Handler
$router->set404(function() {
header('HTTP/1.1 404 Not Found');
echo '404, route not found!';
});
// Static route: / (homepage)
$router->get('/', function() {
echo '<h1>bramus/router</h1><p>Try these routes:<p><ul><li>/hello/<em>name</em></li><li>/blog</li><li>/blog/<em>year</em></li><li>/blog/<em>year</em>/<em>month</em></li><li>/blog/<em>year</em>/<em>month</em>/<em>day</em></li></ul>';
});
// Dynamic route: /hello/name
$router->get('/hello/(\w+)', function($name) {
echo 'Hello ' . htmlentities($name);
});
// Dynamic route with (successive) optional subpatterns: /blog(/year(/month(/day(/slug))))
$router->get('/blog(/\d{4}(/\d{2}(/\d{2}(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
if (!$year) { echo 'Blog overview'; return; }
if (!$month) { echo 'Blog year overview (' . $year . ')'; return; }
if (!$day) { echo 'Blog month overview (' . $year . '-' . $month . ')'; return; }
if (!$slug) { echo 'Blog day overview (' . $year . '-' . $month . '-' . $day . ')'; return; }
echo 'Blogpost ' . htmlentities($slug) . ' detail (' . $year . '-' . $month . '-' . $day . ')';
});
// Thunderbirds are go!
$router->run();
(Yes, you must get your PCRE mojo on in order to define dynamic routes)
bramus/router
also supports before route middlewares, before router middlewares, and after router middleware. These features allow one to integrate bramus/router
with their favorite library (logging, templating, …):
$router = new \Bramus\Router\Router();
$tpl = new \Acme\Template\Template();
$router->get('/', function() use ($tpl) {
$tpl->load('home.tpl');
$tpl->setdata(array(
'name' => 'Bramus!'
));
});
$router->run(function() use ($tpl) {
$tpl->display();
});
An extensive writeup of these features is available on GitHub.
A final note worth mentioning is that bramus/router
is installable via Composer and is unit tested.
bramus/router
(GitHub) →
bramus/router
on Packagist →
bramus/router
Travis CI build status →
Is it possible to add file-extension (like .html) to the router? Could the movie database be like this?
/movies.html (overview)
/movies,2.html (overview page 2)
/movie/123.html (movie detaisl for movie id 123)
I cannot find a solution to add .html as extension.
Thanks so far!
Hi,
I’m trying to understand how your router works, but I’m stuck here:
My blog class is located in /module/blog/Blog.css,
and I’m trying to do something like:
$router->get(‘/blog’, ‘\module\blog\[email protected]’);
Content of blog class is just basic like:
class Blog
{
function Index() {
print ‘Blog Page’;
}
}
But for some reason I can get it to print Blog page, and no errors are thrown