public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } if ($method === 'middleware') { // 调用了RouteRegistrar的attribute方法 只是挂载路由属性 return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters); } return (new RouteRegistrar($this))->attribute($method, $parameters[0]); }
Illuminate\Routing\RouteRegistrar::__call方法
public function __call($method, $parameters) { if (in_array($method, $this->passthru)) { // 当使用get post等方法的时候 return $this->registerRoute($method, ...$parameters); } if (in_array($method, $this->allowedAttributes)) { if ($method === 'middleware') { return $this->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters); } // dd($method); // namespace return $this->attribute($method, $parameters[0]); } throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); }
Illuminate\Routing\RouteRegistrar::group方法
public function group($callback) { // dd($this->attributes, $callback); // array:2 [▼ // "middleware" => array:1 [▼ // 0 => "web" // ] // "namespace" => "App\Http\Controllers" // ] // "/home/vagrant/code/test1/routes/web.php" // 查看Router的group方法 $this->router->group($this->attributes, $callback); }
Router::group方法
public function group(array $attributes, $routes) { $this->updateGroupStack($attributes); // 查看loadRoutes方法 /home/vagrant/code/test1/routes/web.php $this->loadRoutes($routes); array_pop($this->groupStack); } protected function loadRoutes($routes) { if ($routes instanceof Closure) { // 用于闭包嵌套 laravel的路由是可以随意潜逃组合的 $routes($this); } else { // 加载路由文件 /home/vagrant/code/test1/routes/web.php (new RouteFileRegistrar($this))->register($routes); } }
Illuminate\Routing\RouteFileRegistrar 文件
protected $router; public function __construct(Router $router) { $this->router = $router; } public function register($routes) { $router = $this->router; // 终于加载到了路由文件 // require("/home/vagrant/code/test1/routes/web.php"); // 看到这里就到了大家熟悉的Route::get()等方法了 // 道友们可能已经有了有趣的想法: 可以在web.php等路由文件中继续require其他文件 // 便可实现不同功能模块的路由管理 require $routes; }
了解了理由加载流程,下面举个简单例子,laravel如何注册一个路由
// web.php中 Route::get('routecontroller', "\App\Http\Controllers\Debug\TestController@index"); // 跳转到Router的get方法 /** * Register a new GET route with the router. * * @param string $uri * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function get($uri, $action = null) { // dump($uri, $action); // $uri = routecontroller // $action = \App\Http\Controllers\Debug\TestController@index // 跳转到addRoute方法 return $this->addRoute(['GET', 'HEAD'], $uri, $action); } /** * Add a route to the underlying route collection. * * @param array|string $methods * @param string $uri * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ // ['GET', 'HEAD'], $uri, $action public function addRoute($methods, $uri, $action) { // routes是routecollection实例 // 跳转到createRoute方法 // 跳转到RouteCollection的add方法 return $this->routes->add($this->createRoute($methods, $uri, $action)); } /** * Create a new route instance. * * @param array|string $methods * @param string $uri * @param mixed $action * @return \Illuminate\Routing\Route */ // ['GET', 'HEAD'], $uri, $action protected function createRoute($methods, $uri, $action) { // 跳转到actionReferencesController方法 if ($this->actionReferencesController($action)) { $action = $this->convertToControllerAction($action); // dump($action); // array:2 [▼ // "uses" => "\App\Http\Controllers\Debug\TestController@index" // "controller" => "\App\Http\Controllers\Debug\TestController@index" // ] } // 创建一个对应路由规则的Route实例 并且添加到routes(collection)中 // 返回到上面的addRoute方法 // 请自行查看Route的构造方法 $route = $this->newRoute( // dump($this->prefix); // routecontroller $methods, $this->prefix($uri), $action ); if ($this->hasGroupStack()) { $this->mergeGroupAttributesIntoRoute($route); } $this->addWhereClausesToRoute($route); return $route; } /** * Determine if the action is routing to a controller. * * @param array $action * @return bool */ // 判断是否路由到一个控制器 protected function actionReferencesController($action) { // 在此例子中Route::get方法传递的是一个字符串 if (! $action instanceof Closure) { // 返回true return is_string($action) || (isset($action['uses']) && is_string($action['uses'])); } return false; }
RouteCollection的add方法