private function matchRoute(string $route, string $url, &$matches, $value = null)
    {
        switch ($this->getParsingMode($route)) {
            case self::MODE_REGEX:
                // Evaluate & remove first match (full route)
                $matched    = preg_match(self::buildRegex($route, !is_null($value)), $url, $matches);
                array_shift($matches);
                break;

            case self::MODE_STRING:
                // final route
                if (is_null($value)) {
                    $matched = $route === $url;
                    $matches = [];

                    // route prefix
                } else {
                    $matched = empty($route) ? empty($url) : strpos($url, $route) === 0;
                    $matches = [str_replace($route, '', $url)];
                }
                break;
        }

        // Route matches
        if (is_null($value)) {
            return $matched;
        }

        // value is sub-routes array
        $sub_routes = !is_callable($value) && is_array($value);
        return $matched && $sub_routes;
    }