I want to know the difference between a URL Router and a Dispatcher. What are they and what each of them do?
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.
foreach
loop at the end of class Router with if (isset($this->routes[$method][$path])) {return $this->routes[$method][$path]}
. Thank you very much. –
Racing resolve($routeData) : ?callable
method on it that the Dispatcher passes the resolved route data to; it will always return a callable or null. A CallableResolverChain
could loop through a series of CallableResolver until one matches. –
Intercalary Route is a reference to a resource whereas Dispatching is an action of fetching the said resource.
© 2022 - 2024 — McMap. All rights reserved.