root = new PathSegment(type: PathSegmentType::Root); } public function root(): PathSegment { return $this->root; } /** @return string[] */ private function splitPath(string $path): array { $split = explode('/', rtrim($path, '/')); array_shift($split); return $split; } public function findSegment(string $path): ?PathSegmentMatch { $pathSplit = $this->splitPath($path); $seg = $this->root(); $params = []; while (($v = array_shift($pathSplit)) !== null && null !== $seg) { $seg = $seg->findChild($v); if (PathSegmentType::Parameter === $seg?->getType()) { $params[$seg->getValue() ?? ''] = $v; } } return null === $seg ? null : new PathSegmentMatch( segment: $seg, parameters: $params ); } public function dispatch(RequestInterface $request): ResponseInterface { $uri = $request->getUri(); $match = $this->findSegment($uri->getPath()); if (null === $match) { throw new NotFoundException(); } $segment = $match->segment; $method = $request->getMethod(); $method = ( HttpMethod::tryFrom(strtolower($method)) ?? throw new UnknownMethodException() ); $route = $segment->getRoute($method); if (null === $route) { throw new NotFoundException(); } return $route($request); } }