Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
simple routing library with type hints
<?php
require __DIR__.'/routes.php';
use badphp\routes\{
function get,
function post,
function lookup
};
# let's create some routes
$routes = [];
$routes[] = get('/index', function () {
return "Hello everyone!\n";
});
$routes[] = get('/welcome/<name>', function ($params) {
return "Welcome, {$params['name']}!\n";
});
$routes[] = post('/users', function () {
return "User created!\n";
});
# match request against routes
list($func, $params) = lookup($routes, $argv[1], $argv[2]);
if ($func === null) {
echo "Sorry, don't know what you mean!\n";
exit;
}
# invoke matching action + args any way you like
echo $func($params);
<?php
declare(strict_types=1);
namespace badphp\routes;
# get route mapper
function post(string $expr, callable $func): callable {
return route('POST', $expr, $func);
}
# get route mapper
function get(string $expr, callable $func): callable {
return route('GET', $expr, $func);
}
# get route mapper
function put(string $expr, callable $func): callable {
return route('PUT', $expr, $func);
}
# get route mapper
function delete(string $expr, callable $func): callable {
return route('DELETE', $expr, $func);
}
# creates a callable that ma
function route(string $verb, string $expr, callable $func): callable {
# create lambda that does the route matching
return function ($r_verb, $r_path) use ($verb, $expr, $func): array {
$r_verb = strtoupper(trim($r_verb));
$r_path = trim($r_path, '/');
# method mismatch
if ($r_verb !== strtoupper(trim($verb))) {
return [null, null];
}
# match requested path against route, while picking out symbols
$expr = preg_replace(
['@<([^:]+)>@U', '@<([^:]+)(:(.+))?>@U'],
['<$1:[^/]+>', '(?<$1>$3)'],
trim($expr, '/')
);
# mismatch
if (!preg_match('@^'.$expr.'$@', $r_path, $params)) {
return [null, null];
}
# process matched route symbols
$params = array_map('urldecode', array_intersect_key(
array_slice($params, 1),
array_flip(array_filter(array_keys($params), 'is_string'))
));
return [$func, $params];
};
}
# looks up matching callable for method + path
function lookup(array $routes, string $verb, string $path): array {
# iterate over routes, and try to match the request
foreach ($routes as $route) {
list($func, $args) = $route($verb, $path);
if ($func !== null) {
return [$func, $args];
}
}
# no matching route
return [null, null];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment