1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
<?php
declare(strict_types=1);
// Regex-based HTTP router that dispatches requests to controller methods.
namespace App;
class Router
{
private array $routes = [];
public function get(string $path, string $controller, string $method): void
{
$this->routes[] = ['GET', $path, $controller, $method];
}
public function post(string $path, string $controller, string $method): void
{
$this->routes[] = ['POST', $path, $controller, $method];
}
public function dispatch(): void
{
$requestMethod = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = rtrim($uri, '/') ?: '/';
foreach ($this->routes as [$method, $path, $controller, $action]) {
if ($method !== $requestMethod) {
continue;
}
// Convert route placeholders to named regex capture groups.
// Example with route '/post/{id}' and request '/post/42':
// 1. preg_replace turns '{id}' into '(?P<id>[^/]+)'
// result: '#^/post/(?P<id>[^/]+)$#'
// 2. preg_match against '/post/42' produces:
// [0 => '/post/42', 'id' => '42', 1 => '42']
// 3. array_filter keeps only string keys: ['id' => '42']
// 4. PostController->show('42') is called
$pattern = preg_replace('#\{(\w+)\}#', '(?P<$1>[^/]+)', $path);
$pattern = '#^' . $pattern . '$#';
if (preg_match($pattern, $uri, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
$controllerClass = "App\\Controllers\\$controller";
$instance = new $controllerClass();
$instance->$action(...array_values($params));
return;
}
}
http_response_code(404);
echo '404 Not Found';
}
}
|