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 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。