输入banner图图片脚本导航/分类

写给大忙人的你,ThinkPHP路由初始化

路由是项目开发中比较重要的一个环节,每个项目都会使用路由进行管理接口,接下来本文会从源码方面带大家一起学习路由。

前言

使用框架写过项目的肯定都使用过路由,使用路由来进行接口的管理,那么为什么要使用路由呢!

使用路由会保护项目的真实请求路径。

使请求地址更加规范和简洁,在开发过程中方法名有时候会很长,就可以直接使用路由进行简洁处理。

可以统一对请求请求进行拦截并且进行权限检查的操作。

并且在5.1版本支持了注解路由,方便在开发的过程中进行调试。

方便直接对请求进行缓存,并且还支持了路由中间件。

接下来咔咔会对路由的方方面面进行全面的解析,并且会给大家带上脑图方便大家最直观的预览。

image.png


执行流程图

一、路由初识化简单分析

在框架执行流程那一篇文章中,都知道路由初始化是在初始化应用那个过程中执行的。

image.png

路由初始化位置

然后进入到routeInit这个方法,进行代码解析。

来到这个方法先看代码注释,注释为导入路由定义规则。

这段代码的全部我给复制出来了,接下来就是对这段代码进行解析。image.png

导入路由定义规则
/**
* 路由初始化 导入路由定义规则
* @access public
* @return void
*/

public function routeInit()
{
// 路由检测
// scandir:返回置顶目录的文件数组形式
$files = scandir($this->routePath);
foreach ($files as $file) {
if (strpos($file, '.php')) {
$filename = $this->routePath . $file;
// 导入路由配置
$rules = include $filename;
if (is_array($rules)) {
$this->route->import($rules);
}
}
}

if ($this->route->config('route_annotation')) {
// 自动生成路由定义
if ($this->appDebug) {
$suffix = $this->route->config('controller_suffix') || $this->route->config('class_suffix');
$this->build->buildRoute($suffix);
}

$filename = $this->runtimePath . 'build_route.php';

if (is_file($filename)) {
include $filename;
}
}
}

首先会获取route目录下的文件,函数scandir会返回指定目录的文件并且用数组形式返回。

这里返回结果有三个,第一个为当前目录,第二个为父级目录。这俩个数据不用过多追究。

image.png
route目录下的文件
image.png
返回结果

接着就会将route目录下存在php结尾的文件给导入进来,也就是route.php文件。

image.png
导入路由配置

当把路由文件导入进来之后,进行了一次判断然后进行导入规则。

但是在路由文件可以看到是没有返回任何数据的。

image.png
路由文件

路由文件的return演示

那么这里的return是干嘛的呢!在5.1版本之前是没有这一操作的,但是在5.1是存在的,接下来咔咔给大家演示一下这个使用方法。

首先在路由文件的return中配置一条数据。

image.png
路由文件配置新的数据

然后在index文件中创建一个新的方法vpn

image.png
index文件配置的新方法

此时可以直接访问路由vpn即可。

image.png
返回结果

当route文件的return存在的数据的时候,就会执行到$this->route->import($rules);这一步,本节暂时不对这里做出探讨,会在后文中大家详细说明。

下半截源码阅读

image.png
路由初始化下半部分

第一行代码知道这里的数据是从哪里来的吗?

在应用初始化的initialize方法中,执行了init方法,在init方法中执行了容器中实例进行配置更新,在哪里进行设置的。如下图

也就说在这里给路由添加的配置,并且可以看到路由的配置文件是来源于app配置文件。

image.png
路由配置的由来

想要知道这个配置是干什么的就需要从根源去追溯,所以就需要到app的配置文件中去寻找。

可以看到这个参数指的是注解路由的开关。

image.png
app配置文件

在紧接着就是根据注释自动生成路由规则,这一块的代码暂时就说到这里,下文会对这些代码进行详细的说明。

二、通过定义路由再谈门面

这里只是简单提一下,关于路由的一些使用方法之类的就可以直接去文档去看了,咔咔也不用做搬运工在搬过来。

先在路由文件定义一个kaka的路由。

image.png
路由文件

但是这个get方法是怎么执行的呢!代码追踪也直接追不过去,那么这个时候应该怎么做。

第一种办法,在框架中所有的基础类都是注册了门面模式的,所以在路由里边引入facade就可以进行代码追踪了。

但是既然都把门面模式的源码都看了怎么还会去使用第一种办法,肯定要把其中的一些小细节给扒出来。

在base文件中已经注册了门面的别名了,所以说在引入文件时可以使用use Config,也可以使用use think\facade\Config;

image.png
注册类库别名

这个时候就会来到thinkphp/library/think/facade/Config.php这个文件。

可以看到是继承了门面类的。

image.png
config的门面文件

来到Facade这个类中,拉到文件最后可以看到一个方法__callStatic,这个方法是当调用不存在的静态的方法时就会执行这个方法。

image.png
门面类方法

最后就会去执行创建门面类的方法,最终会通过容器返回返回对应的实例,比如使用的是Config,最终就会返回Config的这类的实例。

image.png
创建门面类方法

最后就会回到开始,使用call_user_func_array进行执行对应实例的方法。

static::createFacade()会返回Config的对应实例。

image.png
最终执行方法

这一块内容就说到这里了,虽然说之前在门面中也提到了但是在这里在回顾一下也是很有必要的,为故而知新嘛!

三、路由定义rule方法中的$this->group到底执行了什么

image.png
执行流程图

通过定义路由再谈门面这一节中,就可以知道下图中的rule方法会执行那个类的那个方法。

image.png
路由文件

根据之前咔咔给大家介绍的方法就可以知道最终会执行到thinkphp/library/think/Route.php这个文件中的rule方法。

image.png
注册路由规则

这里就会出现一个问题就是这个group是什么,是怎么执行的,其实在上边的图已经描述的很明白了。

咔咔在用文字给大家在说一遍,可以对照着进行查看源码。

先看一下这个方法熟悉不熟悉。

没错这个方法在容器那一节中进行了特别的讲解,如果不明白的去前言查看之前的文章进行查看。

那么这个方法在哪里执行的,咔咔就直接说了,就不说的那么细了。

image.png
route类中的make方法

当使用Route::rule();时就会执行到门面的__callStatic方法。

这个方法已经说了好多次了,当执行的静态方法不存在时就会执行。

image.png
门面的魔术方法

然后就会去执行createFacade这个方法。

在这个方法需要特别注意最后一行,也就是圈出来的哪一行代码。

这里需要注意一下static::class,它返回的就是Route类,至于是怎么返回的之前也说过,如果不会的可以评论区见哈!

所以make方法的第一个参数就是Route。

image.png
进入容器方法

接着就会进入到容器类的make方法,在这个方法中,注意咔咔圈的俩处。

在容器类中一定要注意的四个属性,咔咔给大家画了出来。

image.png
容器类的四大属性

第一次进来会存入到容器标识名中。

并且第二次执行make方法时传的是标识名的值。

直到这里就会执行到咔咔圈的第二处,执行invokeClass这个方法。

image.png
make方法

来到invokeClass方法中。

在这个方法中主要使用的是反射的知识。

首先会把传过来的think\Route,进行反射类的实例化。

然后会去判断think\Route中是否存在__make方法。

image.png
invokeClass方法

最后就会去执行Route类的__make方法。

并且进行依赖注入App类和Config类。

同时进行了实例化了本类就是代码$route = new static($app, $config);

那么就会去执行构造函数。

image.png
route类中的make方法

接着来到构造函数的方法中查看。

这里一定要注意第二步的注释,这个已经说了很多次了。

如果有疑问就是为什么使用了ArrayAccess。

咔咔就给大家捋一下,首先App类是继承的Container类。

Container类又继承着ArrayAccess类,所以就可以使用像之前的说,像数组一样访问对象。

  • 注入的App类
  • 此处使用了ArrayAccess像数组一样访问对象,但是$app中不存在request属性,所以就会去执行容器类中的__get魔术方法,在__get方法中调用的是容器中的make方法,第一个参数为request,最终会返回request的实例。
  • 注入的config类
  • 此属性返回域名,
  • 初始化默认域名
image.png
Route文件的构造函数

接着就会来到方法setDefaultDomain

这里需要注意一下咔咔圈的地方,在这一节的开头就使用的这个属性来执行的rule中的addRule方法。

这个group就是think\Route\Domain这个类。

又因为think\Route\Domain继承着think\Route\Group

image.png
继承

所以会执行到think\Route\Group到这个类里边。

这下所有的流程就都已经理顺了。

image.png
初始化默认域名

通过上面的这一顿分析和刨铣相信大家对这一块的内容就十分了解了。

四、路由规则预处理

接下来的内容就是对路由规则的处理方式进行解析。

image.png
路由规则处理方法

这几个参数就对前俩个做一个简单的打印,然后看一下这俩个参数分别都是什么。

参数rule

image.png
参数rule

参数$route

image.png
参数route

可以看到这俩个参数几个就是 路由的前半部分,一个是路由的后半部分。

image.png
路由文件

从而就可以得知代码会执行到下图第一处圈起来的地方。

image.png
addRule方法

此时需要注意一点就是在上图中圈起来的第二处地方,这个地方会在什么时候执行呢!

就是当下图路由这样设置的时候才会执行那段代码。

这里的路由设置只是为了做演示,在实际工作中不能这样设置路由啊!第二个路由地址会把第一个路由地址给覆盖的。

image.png
路由文件

接着代码就会执行到创建路由规则实例,也就是下图圈出来的地方。

image.png
创建路由规则实例

关于创建路由规则实例的几个参数需要进行简单的介绍一下

第一个参数:$this->router

image.png
参数设置

第二个参数:$this,就是指的think\route\Domain

接下来的几个地址就是路由规则和地址,就没有必要看了,主要就是第一个参数。

接下来就需要进入到创建路由规则实例的方法中

代码就会追踪到thinkphp/library/think/route/RuleItem.php这个类中。

在这个类中做的事情就是设置规则,也就是下图咔咔圈出来的地方。

image.png
创建路由规则实例的本类

路由规则预处理setRule方法解读。

上图中最后执行的流程就会来到setRule这个方法。

这段代码没有我们眼看这那么容器阅读,接下来就跟着咔咔一步一步的去阅读这块代码。

image.png
路由规则预处理

1.首先代码就会执行这部分

image.png
路由预处理第一部分代码

从一开始就进行了一个简单的判断$,那么这个是从哪里过来的呢!

在文件thinkphp/library/think/route/RuleGroup.php这里就对$进行了处理。

image.png
thinkphp/library/think/route/RuleGroup.php

所以说在什么情况下会执行预处理的第一部分呢!

我们来看一下简单的案例。

image.png
设置路由做测试

然后在路由预处理中进行打印,就会发现打印结果后边会多一个$符号。

image.png
在路由规则预处理中进行打印
image.png
打印结果

substr介绍

这里对substr进行简单的说明一下,碰到每一个知识点都简单的回顾一下。

这个方法用来字符串截取。

参数一:需要截取的字符串

参数二:从什么位置开始截取,正数从左往右,负数结