'([0-9]+)', '{slug}' => '([a-zA-Z0-9\-]+)', '{any}' => '(.+)' ]; /** * Register a GET route */ public function get(string $path, string $handler): void { $this->addRoute('GET', $path, $handler); } /** * Register a POST route */ public function post(string $path, string $handler): void { $this->addRoute('POST', $path, $handler); } /** * Register a PUT route */ public function put(string $path, string $handler): void { $this->addRoute('PUT', $path, $handler); } /** * Register a DELETE route */ public function delete(string $path, string $handler): void { $this->addRoute('DELETE', $path, $handler); } /** * Add route to collection */ private function addRoute(string $method, string $path, string $handler): void { $this->routes[$method][] = [ 'path' => $path, 'handler' => $handler, 'pattern' => $this->compilePattern($path), 'params' => $this->extractParams($path) ]; } /** * Compile route pattern for regex matching */ private function compilePattern(string $path): string { // First replace placeholders with regex patterns $pattern = $path; foreach ($this->patterns as $placeholder => $regex) { $pattern = str_replace($placeholder, $regex, $pattern); } // Escape only the non-regex parts $pattern = preg_quote($pattern, '/'); // Restore the regex patterns that were escaped foreach ($this->patterns as $placeholder => $regex) { $escapedRegex = preg_quote($regex, '/'); $pattern = str_replace($escapedRegex, $regex, $pattern); } return '/^' . $pattern . '$/'; } /** * Extract parameter names from route */ private function extractParams(string $path): array { preg_match_all('/\{([^}]+)\}/', $path, $matches); return $matches[1] ?? []; } /** * Match request against routes */ public function match(string $method, string $uri): ?array { if (!isset($this->routes[$method])) { return null; } foreach ($this->routes[$method] as $route) { if (preg_match($route['pattern'], $uri, $matches)) { // Remove full match, keep only captured groups array_shift($matches); // Map parameters $params = []; foreach ($route['params'] as $index => $paramName) { $params[$paramName] = $matches[$index] ?? null; } return [ 'handler' => $route['handler'], 'params' => $params, 'module' => $this->extractModule($route['handler']) ]; } } return null; } /** * Extract module name from handler */ private function extractModule(string $handler): string { // Handler formats supported: // - "Home\\Controller@index" → module "Home" // - "Controller@index" when module implied by route context $parts = explode('\\', $handler); return $parts[0] ?: 'Default'; } /** * Get all registered routes */ public function getRoutes(): array { return $this->routes; } }