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[^/]+)' // result: '#^/post/(?P[^/]+)$#' // 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'; } }