/** * Add a Route instance to the collection. * * @param \Illuminate\Routing\Route $route * @return \Illuminate\Routing\Route */ public function add(Route $route) { // 跳转吧 $this->addToCollections($route); $this->addLookups($route); // 最终一路返回到Router的get方法 所以我们可以直接打印web.php定义的路由规则 return $route; } /** * Add the given route to the arrays of routes. * * @param \Illuminate\Routing\Route $route * @return void */ protected function addToCollections($route) { $domainAndUri = $route->getDomain().$route->uri(); // dump($route->getDomain(), $route->uri()); null routecontroller foreach ($route->methods() as $method) { // 将路由规则挂载到数组 方便匹配 $this->routes[$method][$domainAndUri] = $route; } // 将路由规则挂载的数组 方便匹配 $this->allRoutes[$method.$domainAndUri] = $route; }
至此就生成了一条路由 注意我这里将注册api路由进行了注释,并且保证web.php中只有一条路由规则
以上是路由的加载 这部分是在$this->bootstrap()方法中完成的,还远没有到达路由分发和匹配的阶段,希望大家能够理解,至此路由规则生成完毕 保存到了RouteCollection实例中,每个路由规则都是一个Route对象,供请求进行匹配
下面根据此条路由进行匹配,并执行返回结果
我们回到Illuminate\Routing\RouteCollection::match方法
public function match(Request $request) { // 获取符合当前请求动作的所有路由 // 是一个Route对象数组 每一个对象对应一个route规则 $routes = $this->get($request->getMethod()); // 匹配到当前请求路由 $route = $this->matchAgainstRoutes($routes, $request); if (! is_null($route)) { // 将绑定了请求的Route实例返回 return $route->bind($request); } $others = $this->checkForAlternateVerbs($request); if (count($others) > 0) { return $this->getRouteForMethods($request, $others); } throw new NotFoundHttpException; } // 该方法中大量使用了collect方法 请查看laravel手册 protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true) { // dump(get_class_methods(get_class(collect($routes)))); // dump(collect($routes)->all()); // items数组 protected属性 // dump(collect($routes)->items); // items属性是一个数组 // 当注册一个兜底路由的时候 (通过Route::fallback方法)对应$route的isFallback会被设为true // partition方法根据传入的闭包将集合分成两部分 // 具体实现可以查看手册 集合部分 [$fallbacks, $routes] = collect($routes)->partition(function ($route) { return $route->isFallback; }); // 将兜底路由放到集合后面 并且通过first方法找到第一个匹配的路由 return $routes->merge($fallbacks)->first(function ($value) use ($request, $includingMethod) { return $value->matches($request, $includingMethod); }); }
Router文件
protected function findRoute($request) { // 可以打印$route 你会发现和你在web.php中打印的是同一个Route对象 $this->current = $route = $this->routes->match($request); // 将匹配到的路由实例挂载到容器 $this->container->instance(Route::class, $route); return $route; } public function dispatchToRoute(Request $request) { // 跳转到runRoute方法 return $this->runRoute($request, $this->findRoute($request)); } protected function runRoute(Request $request, Route $route) { // 给request帮顶当前的route 可以使用$request->route()方法 获取route实例 // 你也可以随时在你的业务代码中通过容器获得当前Route实例 // app(Illuminate\Routing\Route::class) $request->setRouteResolver(function () use ($route) { return $route; }); $this->events->dispatch(new RouteMatched($route, $request)); // 开始准备响应了 return $this->prepareResponse($request, // 跳转到runRouteWithinStack方法 $this->runRouteWithinStack($route, $request) ); } 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 我们跳转到$route->run方法 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() ); }); }
Route::run方法 注意此方法的返回值是直接从匹配的控制器或者闭包中返回的