本篇文章給大家帶來的內容是關於Laravel框架下路由的使用(源碼解析),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。 前言 我的解析文章並非深層次多領域的解析攻略。但是參考著開發文檔看此類文章會讓你在日常開發中更上一層樓。 廢話不多說,我們開始本章的講解。 入口 Laravel啟 ...
本篇文章給大家帶來的內容是關於Laravel框架下路由的使用(源碼解析),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
前言
我的解析文章並非深層次多領域的解析攻略。但是參考著開發文檔看此類文章會讓你在日常開發中更上一層樓。
廢話不多說,我們開始本章的講解。
入口
Laravel啟動後,會先載入服務提供者、中間件等組件,在查找路由之前因為我們使用的是門面,所以先要查到Route的實體類。
註冊
第一步當然還是通過服務提供者,因為這是laravel啟動的關鍵,在 RouteServiceProvider
內載入路由文件。
1
2
3
4
5
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 );
}
|