[], 'post' => [] ]; private array $groupStack = []; public function get(string $id, string $pattern, array $handler): void { $this->addRoute('get', $id, $pattern, $handler); } public function post(string $id, string $pattern, array $handler): void { $this->addRoute('post', $id, $pattern, $handler); } public function group(string $pattern, Closure $group): void { $this->groupStack[] = $pattern; $group($this); array_pop($this->groupStack); } public function getRoute(string $id): ?IRoute { if (!isset($this->routes[$id])) { return null; } return $this->routes[$id]; } public function match(string $method, string $uri): ?array { $path = $uri === '/' ? [] : explode('/', ltrim($uri, '/')); $groupNumber = count($path); // response to HEAD request with the GET content if ($method === 'head') { $method = 'get'; } if (!isset($this->searchTable[$method][$groupNumber])) { return null; } foreach ($this->searchTable[$method][$groupNumber] as $route) { if (($parameters = $route->testAgainst($path)) !== null) { return [$route, $parameters]; } } return null; } private function addRoute(string $method, string $id, string $pattern, array $handler): void { if (isset($this->routes[$id])) { throw new \Exception('Route already exists: ' . $id); } $pattern = array_merge($this->groupStack, $pattern === '' ? [] : explode('/', $pattern)); $route = new Route($id, $pattern, $handler); $groupNumber = count($pattern); $this->searchTable[$method][$groupNumber][] = $route; while (preg_match('/^{\\w+\\?}$/', end($pattern)) === 1) { $groupNumber--; array_pop($pattern); $this->searchTable[$method][$groupNumber][] = $route; } $this->routes[$id] = $route; } }