Skip to content

解析路由

上面说到,请求经过中间件之后,最终调用dispatchToRouter()方法,接下来分析dispatchToRouter()方法的实现。

php
protected function dispatchToRouter()
{
    return function ($request) {
        // 将request绑定到容器中
        $this->app->instance('request', $request);
        // 路由匹配
        return $this->router->dispatch($request);
    };
}

查看dispatch()方法

源码,

php
public function dispatch(Request $request)
{
    // 将请求给Router类的currentRequest变量
    $this->currentRequest = $request;
    // 继续看下面的dispatchToRoute()方法
    return $this->dispatchToRoute($request);
}

public function dispatchToRoute(Request $request)
{
    return $this->runRoute($request, $this->findRoute($request));
}

先看findRoute()方法,

php
protected function findRoute($request)
{
    // 查找匹配的路由,如果路由不存在则抛出NotFoundHttpException异常
    $this->current = $route = $this->routes->match($request);
    // 绑定路由到容器中
    $route->setContainer($this->container);
    // 将路由绑定到容器中
    $this->container->instance(Route::class, $route);

    return $route;
}
# -----------------------------------------
// $this->routes 为RouteCollection实例
public function __construct(Dispatcher $events, Container $container = null)
{
    $this->events = $events;
    $this->routes = new RouteCollection;
    $this->container = $container ?: new Container;
}
# -------------------------------------------
// match方法
public function match(Request $request)
{
    // 获取对应请求方法的所有路由
    $routes = $this->get($request->getMethod());

    // First, we will see if we can find a matching route for this current request
    // method. If we can, great, we can just return it so that it can be called
    // by the consumer. Otherwise we will check for routes with another verb.
    $route = $this->matchAgainstRoutes($routes, $request);

    return $this->handleMatchedRoute($request, $route);
}

查看runRoute()方法

php
protected function runRoute(Request $request, Route $route)
{
    $request->setRouteResolver(function () use ($route) {
        return $route;
    });
    // 触发RouteMatched事件
    $this->events->dispatch(new RouteMatched($route, $request));
    // 返回响应内容
    return $this->prepareResponse($request,
        $this->runRouteWithinStack($route, $request)
    );
}
runRouteWithinStack()方法

返回响应内容

php
protected function runRouteWithinStack(Route $route, Request $request)
{
    $shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
                            $this->container->make('middleware.disable') === true;
    // 这里的中间件可以是全局中间件,也可以是路由中间件
    $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
    // 这里又执行了一次在处理请求时的Pipeline类,只是最后传的匿名函数不同
    // 最终返回响应内容给toResponse()方法
    return (new Pipeline($this->container))
                    ->send($request)
                    ->through($middleware)
                    ->then(function ($request) use ($route) {
                        return $this->prepareResponse(
                            $request, $route->run()
                        );
                    });
}
#--------------------------------------------------------------------
// run方法
public function run()
{
    $this->container = $this->container ?: new Container;

    try {
        /**
         * 判断是否是控制器方法
         * 是则运行控制器的方法
         */
        if ($this->isControllerAction()) {
            /**
             * protected function runController()
             * {
             *     return $this->controllerDispatcher()->dispatch(
             *         $this, $this->getController(), $this->getControllerMethod()
             *     );
             * }
             */
            return $this->runController();
        }
        // 如果不是,则运行回调函数
        return $this->runCallable();
    } catch (HttpResponseException $e) {
        return $e->getResponse();
    }
}
prepareResponse()方法
php
# -----------------------------------------------------------
# prepareResponse()方法,第一个是请求对象,第二个是$this->runRouteWithinStack($route, $request)方法返回的响应内容
public function prepareResponse($request, $response)
{
    return static::toResponse($request, $response);
}
// toResponse()方法
// 判断响应内容是那种类型,然后实例化对应的响应对象
public static function toResponse($request, $response)
{
    if ($response instanceof Responsable) {
        $response = $response->toResponse($request);
    }

    if ($response instanceof PsrResponseInterface) {
        $response = (new HttpFoundationFactory)->createResponse($response);
    } elseif ($response instanceof Model && $response->wasRecentlyCreated) {
        $response = new JsonResponse($response, 201);
    } elseif ($response instanceof Stringable) {
        $response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html']);
    } elseif (! $response instanceof SymfonyResponse &&
                ($response instanceof Arrayable ||
                $response instanceof Jsonable ||
                $response instanceof ArrayObject ||
                $response instanceof JsonSerializable ||
                $response instanceof \stdClass ||
                is_array($response))) {
        $response = new JsonResponse($response);
    } elseif (! $response instanceof SymfonyResponse) {
        $response = new Response($response, 200, ['Content-Type' => 'text/html']);
    }

    if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {
        $response->setNotModified();
    }

    return $response->prepare($request);
}

最终dispatchToRouter()方法返回一个Response对象,然后执行carry()方法

php
 protected function carry()
{
    return function ($stack, $pipe) {
        return function ($passable) use ($stack, $pipe) {
            try {
                // 省略...
                $carry = method_exists($pipe, $this->method)
                                ? $pipe->{$this->method}(...$parameters)
                                : $pipe(...$parameters);

                // 最终return handleCarry这个方法
                // carry是返回的Response对象
                return $this->handleCarry($carry);
            } catch (Throwable $e) {
                return $this->handleException($passable, $e);
            }
        };
    };
}

查看handleCarry()方法

上面内容跑完之后,最终返回的就是一个Response对象,然后响应对象调用toResponse方法,将Request对象从容器中取出传参

php
protected function handleCarry($carry)
{
    return $carry instanceof Responsable
        ? $carry->toResponse($this->getContainer()->make(Request::class))
        : $carry;
}