addRoute('GET', $path, $handler); return $this; } public function post(string $path, array|callable $handler): self { $this->addRoute('POST', $path, $handler); return $this; } public function put(string $path, array|callable $handler): self { $this->addRoute('PUT', $path, $handler); return $this; } public function delete(string $path, array|callable $handler): self { $this->addRoute('DELETE', $path, $handler); return $this; } public function any(string $path, array|callable $handler): self { foreach (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as $method) { $this->addRoute($method, $path, $handler); } return $this; } public function setNotFound(callable $handler): void { $this->notFoundHandler = $handler; } private function addRoute(string $method, string $path, array|callable $handler): void { // Normalize path $path = '/' . trim($path, '/'); if ($path === '//') { $path = '/'; } // Convert {param} to regex pattern (?P[^/]+) $pattern = preg_replace('/\{([a-zA-Z0-9_]+)\}/', '(?P<$1>[^/]+)', $path); $regex = '#^' . $pattern . '$#'; $this->routes[] = [ 'method' => strtoupper($method), 'path' => $path, 'regex' => $regex, 'handler' => $handler, ]; } public function dispatch(Request $request, Response $response): Response { $method = $request->getMethod(); $path = $request->getPath(); foreach ($this->routes as $route) { if ($route['method'] !== $method) { continue; } if (preg_match($route['regex'], $path, $matches)) { // Extract named matches for params $params = []; foreach ($matches as $key => $value) { if (is_string($key)) { $params[$key] = $value; } } $handler = $route['handler']; if (is_callable($handler)) { $result = call_user_func($handler, $request, $response, $params); } elseif (is_array($handler) && count($handler) === 2) { [$controllerClass, $action] = $handler; $controller = new $controllerClass(); $result = call_user_func([$controller, $action], $request, $response, $params); } else { throw new \RuntimeException('Invalid route handler specified.'); } if ($result instanceof Response) { return $result; } if (is_string($result)) { return $response->setContent($result); } return $response; } } // 404 Not Found if ($this->notFoundHandler) { $result = call_user_func($this->notFoundHandler, $request, $response); if ($result instanceof Response) { return $result; } return $response->setStatusCode(404)->setContent((string)$result); } return $response->setStatusCode(404)->setContent('

404 Not Found

The requested route does not exist.

'); } }