本篇文章給你們帶來的內容是關於Laravel框架下路由的使用(源碼解析),有必定的參考價值,有須要的朋友能夠參考一下,但願對你有所幫助。php
前言
個人解析文章並不是深層次多領域的解析攻略。可是參考着開發文檔看此類文章會讓你在平常開發中更上一層樓。laravel
廢話很少說,咱們開始本章的講解。api
入口
Laravel啓動後,會先加載服務提供者、中間件等組件,在查找路由以前由於咱們使用的是門面,因此先要查到Route的實體類。框架
註冊
第一步固然仍是經過服務提供者,由於這是laravel啓動的關鍵,在 RouteServiceProvider
內加載路由文件。dom
1ide 2post 3ui 4this 5url 6 7 |
protected function mapApiRoutes()
{
Route::prefix( 'api' )
->middleware( 'api' )
-> namespace ( $this -> namespace )
->group(base_path( 'routes/api.php' ));
}
|
首先require是不可缺乏的。因路由文件中沒有命名空間。 Illuminate\Routing\Router
下方法
1 2 3 4 5 6 7 8 9 10 |
protected function loadRoutes( $routes )
{
if ( $routes instanceof Closure) {
$routes ( $this );
} else {
$router = $this ;
require $routes ;
}
}
|
隨後經過路由找到指定方法,依舊是 Illuminate\Routing\Router
內有你所使用的全部路由相關方法,例如get、post、put、patch等等,他們都調用了統一的方法 addRoute
1 2 3 4 |
public function addRoute( $methods , $uri , $action )
{
return $this ->routes->add( $this ->createRoute( $methods , $uri , $action ));
}
|
以後經過 Illuminate\Routing\RouteCollection
addToCollections 方法添加到集合中
1 2 3 4 5 6 7 8 9 10 |
protected function addToCollections( $route )
{
$domainAndUri = $route ->getDomain(). $route ->uri();
foreach ( $route ->methods() as $method ) {
$this ->routes[ $method ][ $domainAndUri ] = $route ;
}
$this ->allRoutes[ $method . $domainAndUri ] = $route ;
}
|
添加後的結果以下圖所示
調用
經過 Illuminate\Routing\Router
方法開始運行路由實例化的邏輯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
protected function runRoute(Request $request , Route $route )
{
$request ->setRouteResolver( function () use ( $route ) {
return $route ;
});
$this ->events->dispatch( new Events\RouteMatched( $route , $request ));
return $this ->prepareResponse( $request ,
$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 );
return ( new Pipeline( $this ->container))
->send( $request )
->through( $middleware )
->then( function ( $request ) use ( $route ) {
return $this ->prepareResponse(
$request , $route ->run()
);
});
}
|
在 Illuminate\Routing\Route
下 run 方用於執行控制器的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public function run()
{
$this ->container = $this ->container ?: new Container;
try {
if ( $this ->isControllerAction()) {
return $this ->runController();
}
return $this ->runCallable();
} catch (HttpResponseException $e ) {
return $e ->getResponse();
}
}
|
從上述方法內能夠看出 runController 是運行路由的關鍵,方法內運行了一個調度程序,將控制器 $this->getController()
和控制器方法 $this->getControllerMethod()
傳入到 dispatch
調度方法內
1 2 3 4 5 6 7 |
protected function runController()
{
return $this ->controllerDispatcher()->dispatch(
$this , $this ->getController(), $this ->getControllerMethod()
);
}
|
這裏注意 getController()
纔是真正的將控制器實例化的方法
1 2 3 4 5 6 7 8 9 10 |
public function getController()
{
if (! $this ->controller) {
$class = $this ->parseControllerCallback()[0];
$this ->controller = $this ->container->make(ltrim( $class , '\\' ));
}
return $this ->controller;
}
|
實例化
依舊經過反射加載路由指定的控制器,這個時候build的參數$concrete = App\Api\Controllers\XxxController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public function build( $concrete )
{
if ( $concrete instanceof Closure) {
return $concrete ( $this , $this ->getLastParameterOverride());
}
$reflector = new ReflectionClass( $concrete );
if (! $reflector ->isInstantiable()) {
return $this ->notInstantiable( $concrete );
}
$this ->buildStack[] = $concrete ;
$constructor = $reflector ->getConstructor();
if ( is_null ( $constructor )) {
array_pop ( $this ->buildStack);
return new $concrete ;
}
$dependencies = $constructor ->getParameters();
$instances = $this ->resolveDependencies(
$dependencies
);
array_pop ( $this ->buildStack);
return $reflector ->newInstanceArgs( $instances );
}
|
這時將返回控制器的實例,下面將經過url訪問指定方法,通常控制器都會繼承父類 Illuminate\Routing\Controller
,laravel爲其設置了別名 BaseController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public function dispatch(Route $route , $controller , $method )
{
$parameters = $this ->resolveClassMethodDependencies(
$route ->parametersWithoutNulls(), $controller , $method
);
if (method_exists( $controller , 'callAction' )) {
return $controller ->callAction( $method , $parameters );
}
return $controller ->{ $method }(... array_values ( $parameters ));
}
|
Laravel經過controller繼承的callAction去調用子類的指定方法,也就是咱們但願調用的自定義方法。
1 2 3 4 |
public function callAction( $method , $parameters )
{
return call_user_func_array([ $this , $method ], $parameters );
}
|