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 →

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

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\Blog@Index’);

    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

  3. Could you point me to any resource that integrates some kind of security or login for secured urls? great work, thanks

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.