当前位置: 首页 > 后端技术 > PHP

Laravel源码分析路由的使用

时间:2023-03-29 14:38:42 PHP

前言我的分析文章不是深度多领域的分析攻略。但是参考开发文档阅读此类文章,会让你在日常开发中更上一层楼。话不多说,下面开始本章的讲解。入口Laravel启动后,首先会加载服务提供者、中间件等组件。在寻找路由之前,因为我们使用的是门面,所以首先要找到Route的实体类。注册的第一步当然是通过服务提供者,因为这是laravel启动的关键,路由文件是在RouteServiceProvider中加载的。protectedfunctionmapApiRoutes(){Route::prefix('api')->middleware('api')->namespace($this->namespace)//设置命名空间->group(base_path('routes/api.php'));//生成的路由文件的绝对路径}首先require不可少。因为路由文件中没有命名空间。Illuminate\Routing\Router下的方法protectedfunctionloadRoutes($routes){if($routesinstanceofClosure){$routes($this);}else{$router=$this;需要$路由;}}然后通过routing方法找到指定的路由,依然是Illuminate\Routing\Router包含了你使用的所有路由相关的方法,比如get、post、put、patch等,它们都调用了统一的方法addRoutepublicfunctionaddRoute($methods,$uri,$action){return$this->routes->add($this->createRoute($methods,$uri,$action));}然后通过Illuminate\Routing\添加到集合中RouteCollectionaddToCollections方法protectedfunctionaddToCollections($route){$domainAndUri=$route->getDomain().$route->uri();foreach($route->methods()as$method){$this->routes[$method][$domainAndUri]=$route;}$this->allRoutes[$method.$domainAndUri]=$route;}添加后的结果如下图所示。通过Illuminate\Routing\Router方法调用路由实例化的逻辑。protectedfunctionrunRoute(Request$request,Route$route){$request->setRouteResolver(function()use($route){返回$路线;});$this->events->dispatch(newEvents\RouteMatched($route,$request));返回$this->prepareResponse($request,$this->runRouteWithinStack($route,$request));}....受保护的函数runRouteWithinStack(Route$route,Request$request){$shouldSkipMiddleware=$this->container->bound('middleware.disable')&&$this->container->make('middleware.disable')===true;$middleware=$shouldSkipMiddleware?[]:$this->gatherRouteMiddleware($route);return(newPipeline($this->container))->send($request)->through($middleware)->then(function($request)使用($route){return$this->prepareResponse($request,$route->run()//这里调用run方法);});}在Illuminate\Routing\Route下运行方法用于执行控制器的方法publicfunctionrun(){$this->container=$this->container?:newContainer;尝试{if($this->isControllerAction()){返回$this->runController();//运行路由并做出响应}return$this->runCallable();}catch(HttpResponseException$e){返回$e->getResponse();}}从上面的方法可以看出,runController是路由运行的关键,方法中运行了一个dispatcher,控制器$this->getController()和控制器方法$this->getControllerMethod()是传入dispatch调度方法protectedfunctionrunController(){return$this->controllerDispatcher()->dispatch($this,$this->getController(),$this->getControllerMethod());}这里注意getController()是实例化控制器的真正方法publicfunctiongetController(){if(!$this->controller){$class=$this->parseControllerCallback()[0];//0=>controllerxxController1=>methodnameindex$this->controller=$this->container->make(ltrim($class,'\\'));//交给容器行反射}return$this->controller;}实例化依旧通过加载路由指定的控制器,此时build的参数$concrete=App\Api\Controllers\XxxControllerpublicfunctionbuild($concrete){//如果具体类型实际上是一个闭包,我们将只执行它并//交回函数的结果,这允许函数//用作解析器,以便对这些对象进行更精细的解析。if($concreteinstanceofClosure){return$concrete($this,$this->getLastParameterOverride());}}$reflector=newReflectionClass($concrete);//如果类型不可实例化,则开发人员正在尝试解析//抽象类型,例如抽象类的接口,并且//没有为抽象注册绑定,因此我们需要退出。如果(!$reflector->isInstantiable()){返回$this->notInstantiable($concrete);}$this->buildStack[]=$concrete;$constructor=$反射器->getConstructor();//如果没有构造函数,则意味着没有依赖关系//我们可以立即解析对象的实例,而无需//从这些容器中解析任何其他类型或依赖关系。如果(is_null($constructor)){array_pop($this->buildStack);返回新的$混凝土;}$dependencies=$constructor->getParameters();//一旦我们有了构造函数的所有参数,我们就可以创建每个//依赖实例,然后使用反射实例来创建//这个类的新实例,将创建的依赖注入。$instances=$this->resolveDependencies($dependencies);array_pop($this->buildStack);return$reflector->newInstanceArgs($instances);}这个时候会返回controller的实例,通过下面的url访问指定的方法。一般控制器会继承父类Illuminate\Routing\Controller,laravel为其设置了一个别名BaseControllerpublicfunctiondispatch(Route$route,$control呃,$method){$parameters=$this->resolveClassMethodDependencies($route->parametersWithoutNulls(),$controller,$method);如果(method_exists($controller,'callAction')){return$controller->callAction($method,$parameters);}return$controller->{$method}(...array_values($parameters));}Laravel通过controller继承的callAction调用子类的指定方法,也就是我们要调用的self定义方法publicfunctioncallAction($method,$parameters){returncall_user_func_array([$this,$method],$parameters);}感谢阅读本文,本文源码分析全凭个人理解。如有不妥,请拍砖。希望这篇文章能帮到你。谢谢