bramus/router — A lightweight and simple object oriented PHP Router

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 just GET 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!

(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) {
        'name' => 'Bramus!'

$router->run(function() use ($tpl) {

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 →

Join the Conversation


  1. 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!

  2. 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

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.