3.2.1 - Laravel - 5.6 - Route - 路由配置文件加载 之 Group方法解析
group 方法在路由中起到对固定一批路由统一规则的作用。
简单说就是一个 group 方法下的路由都可以设置相同的路由规则。参考文档的使用一下就明白了。
最最重要的是这个 group 方法也是加载路由配置文件 web.php
的主要方法,laravel 本身把整个路由配置文件视为一个路由的 group 操作。#
直接看 group 的源代码:
public function group(array $attributes, $routes)
{
$this->updateGroupStack($attributes);
$this->loadRoutes($routes);
array_pop($this->groupStack);
}
这里逻辑主要是三步:
1. 首先使用 updateGroupStack 方法更新 groupStack 数组。$this->updateGroupStack($attributes);
groupStack 数组用来存储所有 group 的 attributes 数据。
比如:
middleware – group 下面路由的中间件
namespace – group 对应路由 action 的命名空间
prefix – group 对应路由 url 的前缀
updateGroupStack 源码如下:
protected function updateGroupStack(array $attributes)
{
if (! empty($this->groupStack)) {
$attributes = $this->mergeWithLastGroup($attributes);
}
$this->groupStack[] = $attributes;
}
很简单,如果 groupStack 这个数组不为空,(说明上面还有一些 group 的全局规则)。那么就使用 mergeWithLastGroup 方法 merge 当前的 attributes (attribute 就是当前 group 的规则) 到 groupStack 数组的最后一个数据中。
然后把当前这个 group 的 attributes 加到 groupStack 栈的尾部。这里强调一下尾部因为栈的结构后进先出,最靠近当前 group 的 attributes 数据放在最后。
1.1 然后看下 mergeWithLastGroup 方法。
public function mergeWithLastGroup($new)
{
return RouteGroup::merge($new, end($this->groupStack));
}
a.end($this->groupStack)
:end () 方法获取 groupStack 最后一个数据。
b. 调用 RouteGroup 的 merge 方法组合 attributes 和 group 中的最后一个数据。
这里的 merge 方法细节较多。具体细节放在了下一节 3.2 - Laravel - 5.6 - Route - 路由 group 合并。
2. 回到 group 方法,第二步 $this->loadRoutes($routes);
加载路由
完成更新 groupstack 后,使用 loadRoutes 方法加载路由。代码如下:
protected function loadRoutes($routes)
{
if ($routes instanceof Closure) {
$routes($this);
} else {
(new RouteFileRegistrar($this))->register($routes);
}
}
a. 如果这个 $routes
是一个闭包函数,就直接执行。
b. 否则创建一个 RouteFileRegistrar 对象来调用 register 方法注册这个 $routes
。
2.1 我们看下 RouteFileRegistrar 的 register 方法。
public function register($routes)
{
$router = $this->router;
require $routes;
}
很明了,就是使用 require 引入 $routes
。
这说明
$routes
可以是一个路径。require 可以直接加载整个文件或者文件路径。
** 第二步总结:**
1. 到这里就很明确了。这一步 $this->loadRoutes($routes);
简单说就是:如果 group 方法提供的参数是闭包函数,比如下面这种。(第二个参数是 function 闭包。)
Route::group(['middleware' => ['auth', 'verified']], function() {
Route::get('user_addresses', 'UserAddressesController@index');
....
,这里就会执行这个路由的闭包函数。也就是加载这个路由。执行的是 Route::get () 方法。(get 方法这里仅仅是对这个路由的注册)
2. 否则则会判定这是一个文件路径,会使用 require
引入这个文件。然后依次执行文件中的方法。
这种文件路径的具体的使用的例子在 加载路由配置文件 web.php,api.php 的时候会使用到。
例子如下:路由前期初始化的时候加载配置文件调用的 group 方法如下:
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
这里就是通过 require 加载了 routes/web.php
这个文件。
加载配置文件的具体流程会在章节:
加载RouteServiceProvider
中涉及。这里不再累述。
3. 最后 group () 方法的第三步:完成路由的加载后,需要从 groupStack 中去除刚刚已经添加的路由的属性规则(attribute)。
array_pop($this->groupStack);
为的是不让当前路由的 attribute 不影响其他路由。
在第一步添加的路由属性 attributes 数据要在这里(第三步)删除,保证当前加载的路由 group 属性 attributes 不针对其他路由。
这个说明在注册路由对象的时候 (就是执行 Route::get (), Route::post 方法的时候),并没有执行清理,而是在这里进行了当前路由属性 attributes 的清理。
总结:#
路由的 group 方法在类 Router 中提供。group 方法提供了两种方式来进行路由的加载,一个是闭包,一个是路径的方式。
group 对应的参数 attributes 以栈的形式存储。可以形成一个嵌套,如果存在多个层级的 group 的话。
最后强调下,group 方法是对路由的加载,把一个一个路由代码创建成一个一个对象,然后等待着请求 request 来调用。
举例 :web.php 下面的这段代码将会被 group 方法加载 web.php 执行后,变成一个 route 对象存储其起来,等待请求的到来。
Route::get('connect', 'AccountController@connect')->name('connect');
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: