What is the difference between URL Router and Dispatcher?

YakumaruBR picture YakumaruBR · Jul 28, 2012 · Viewed 22.6k times · Source

I want to know the difference between the URL Router and Dispatcher, because searching on the internet has some interesting things, just do not know if it's because they are similar, or because they reverse the function of each. Can anyone tell me what it is and what each one, and an example?

I do not know the differentiate from URL Router to Dispatcher, the question of content they have on the Internet, sometimes it seems the Dispatcher is the Router, and the Router seems Dispatcher, and end up not knowing what the right of each, what is each one, and how implement each one.

Thank you.

Answer

Charles Sprayberry picture Charles Sprayberry · Jul 29, 2012

How frameworks and libraries interpret the responsibilities of the Router and Dispatcher are going to be different. What I detail below is how I interpret the responsibilities of these two services. It is not to say that this is the only way to interpret it or that other interpretations are wrong.

The Concepts

Routing

This is kinda like asking for directions at a gas station or convenience store. You're going through town and you need to figure out how to get to the nearest hotel. You go in and ask the attendant and they point you off in the correct direction, or at least you hope the directions are correct. Routing is exactly this. A request comes in for a resource, the Router provides the directions necessary for the request to reach the correct resource.

In most major frameworks you're going to be routing a specific request URL to an object and method that will be invoked to complete the request. Often times you'll see the Router also parsing out dynamic arguments from the URL. For example, if you accessed users via /users/1234 where 1234 is the user ID the Router would parse out the ID portion and provide this as part of the directions to the resource.

Dispatching

Dispatching uses the information from the Routing step to actually generate the resource. If the Routing step is asking for directions then Dispatching is the actual process of following those directions. Dispatching knows exactly what to create and the steps needed to generate the resource, but only after getting the directions from the Router.

The Implementations

These example implementations are intentionally very simple and naive. You would not want to use this in any kind of production environment without drastic improvements.

In this example instead of routing to an object and method we're just gonna route to a callable function. This also demonstrates that you don't need to route to an object; as long as the dispatcher can properly get the correct resource you can route to whatever data you want.

First we need something to route against. Let's create a simple Request object that we can match against.

<?php

class Request {

    private $method;
    private $path;

    function __construct($method, $path) {
        $this->method = $method;
        $this->path = $path;
    }

    function getMethod() {
        return $this->method;
    }

    function getPath() {
        return $this->path;
    }

}

Now that we can match against something let's take a look at a simple Router implementation.

<?php

class Router {

    private $routes = [
        'get' => [],
        'post' => []
    ];

    function get($pattern, callable $handler) {
        $this->routes['get'][$pattern] = $handler;
        return $this;
    }

    function post($pattern, callable $handler) {
        $this->routes['post'][$pattern] = $handler;
        return $this;
    }

    function match(Request $request) {
        $method = strtolower($request->getMethod());
        if (!isset($this->routes[$method])) {
            return false;
        }

        $path = $request->getPath();
        foreach ($this->routes[$method] as $pattern => $handler) {
            if ($pattern === $path) {
                return $handler;
            }
        }

        return false;
    }

}

And now we need some way to invoke a configured $handler for a given Request.

<?php

class Dispatcher {

    private $router;

    function __construct(Router $router) {
        $this->router = $router;
    }

    function handle(Request $request) {
        $handler = $this->router->match($request);
        if (!$handler) {
            echo "Could not find your resource!\n";
            return;
        }

        $handler();
    }

}

Now, let's bring it all together and show how to use these simple implementations.

<?php

$router = new Router();
$router->get('foo', function() { echo "GET foo\n"; });
$router->post('bar', function() { echo "POST bar\n"; });

$dispatcher = new Dispatcher($router);

$dispatcher->handle(new Request('GET', 'foo'));
$dispatcher->handle(new Request('POST', 'bar'));
$dispatcher->handle(new Request('GET', 'qux'));

You can see an example of this implementation in action by checking out http://3v4l.org/gbsoJ.

The Wrap Up

This example implementation is supposed to communicate the concept of routing and dispatching. Really there's a lot more to performing these actions than my example. Often the Router will use regex to match against a Request and may look at other Request attributes when matching. Additionally you'll see some libraries utilizing a resolver that interacts with the Router so that you can pass more than just callable functions. Basically, the Resolver would ensure that the $handler matched against can be turned into an invokable function.

Also, there's plenty of examples and implementations for this that you should look at using instead. For my personal projects I like FastRoute for its ease of use and performance. But, nearly all major frameworks have their own implementations. You should check those out too.