> */ private array $routes = []; /** @var array> */ private array $middlewareStack = []; public function get(string $path, callable $action, array $middleware = []): void { $this->addRoute('GET', $path, $action, $middleware); } public function post(string $path, callable $action, array $middleware = []): void { $this->addRoute('POST', $path, $action, $middleware); } public function put(string $path, callable $action, array $middleware = []): void { $this->addRoute('PUT', $path, $action, $middleware); } public function delete(string $path, callable $action, array $middleware = []): void { $this->addRoute('DELETE', $path, $action, $middleware); } public function group(array $attributes, \Closure $callback): void { $groupMiddleware = $attributes['middleware'] ?? []; $this->middlewareStack[] = $groupMiddleware; $callback($this); array_pop($this->middlewareStack); } /** * @param array $middleware */ private function addRoute(string $method, string $path, callable $action, array $middleware = []): void { $stackedMiddleware = []; foreach ($this->middlewareStack as $group) { $stackedMiddleware = array_merge($stackedMiddleware, $group); } $combinedMiddleware = array_merge($stackedMiddleware, $middleware); $this->routes[$method][] = [ 'path' => $path, 'action' => $action, 'middleware' => $combinedMiddleware, ]; } public function dispatch(string $method, string $uri): Response { $uri = parse_url($uri, PHP_URL_PATH) ?? '/'; $routes = $this->routes[$method] ?? []; foreach ($routes as $route) { $pattern = '#^' . preg_replace('#\{(.*?)\}#', '(?P<$1>[^/]+)', $route['path']) . '$#'; if (preg_match($pattern, $uri, $matches)) { $params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY); $handler = $this->applyMiddleware($route['action'], $route['middleware']); $result = $handler($params); if ($result instanceof Response) { return $result; } return new Response((string) $result); } } return new Response('Not Found', 404); } /** * @param callable $action * @param array $middleware */ private function applyMiddleware(callable $action, array $middleware): callable { return array_reduce( array_reverse($middleware), function ($next, $middlewareClass) { $middlewareInstance = new $middlewareClass(); return fn(array $params) => $middlewareInstance->handle($params, $next); }, $action ); } }