时间:2021-07-01 10:21:17 帮助过:57人阅读
“路由是项目开发中比较重要的一个环节,每个项目都会使用路由进行管理接口,接下来本文会从源码方面带大家一起学习路由。
”
使用框架写过项目的肯定都使用过路由,使用路由来进行接口的管理,那么为什么要使用路由呢!
使用路由会保护项目的真实请求路径。
使请求地址更加规范和简洁,在开发过程中方法名有时候会很长,就可以直接使用路由进行简洁处理。
可以统一对请求请求进行拦截并且进行权限检查的操作。
并且在5.1版本支持了注解路由,方便在开发的过程中进行调试。
方便直接对请求进行缓存,并且还支持了路由中间件。
接下来咔咔会对路由的方方面面进行全面的解析,并且会给大家带上脑图方便大家最直观的预览。
在框架执行流程那一篇文章中,都知道路由初始化是在初始化应用那个过程中执行的。
然后进入到routeInit
这个方法,进行代码解析。
来到这个方法先看代码注释,注释为导入路由定义规则。
这段代码的全部我给复制出来了,接下来就是对这段代码进行解析。
/**
* 路由初始化 导入路由定义规则
* @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会返回指定目录的文件并且用数组形式返回。
这里返回结果有三个,第一个为当前目录,第二个为父级目录。这俩个数据不用过多追究。
接着就会将route目录下存在php结尾的文件给导入进来,也就是route.php文件。
当把路由文件导入进来之后,进行了一次判断然后进行导入规则。
但是在路由文件可以看到是没有返回任何数据的。
路由文件的return演示
那么这里的return是干嘛的呢!在5.1版本之前是没有这一操作的,但是在5.1是存在的,接下来咔咔给大家演示一下这个使用方法。
首先在路由文件的return中配置一条数据。
然后在index文件中创建一个新的方法vpn
此时可以直接访问路由vpn即可。
当route文件的return存在的数据的时候,就会执行到$this->route->import($rules);
这一步,本节暂时不对这里做出探讨,会在后文中大家详细说明。
下半截源码阅读
第一行代码知道这里的数据是从哪里来的吗?
在应用初始化的initialize方法中,执行了init方法,在init方法中执行了容器中实例进行配置更新,在哪里进行设置的。如下图
也就说在这里给路由添加的配置,并且可以看到路由的配置文件是来源于app配置文件。
想要知道这个配置是干什么的就需要从根源去追溯,所以就需要到app的配置文件中去寻找。
可以看到这个参数指的是注解路由的开关。
在紧接着就是根据注释自动生成路由规则,这一块的代码暂时就说到这里,下文会对这些代码进行详细的说明。
这里只是简单提一下,关于路由的一些使用方法之类的就可以直接去文档去看了,咔咔也不用做搬运工在搬过来。
先在路由文件定义一个kaka的路由。
但是这个get方法是怎么执行的呢!代码追踪也直接追不过去,那么这个时候应该怎么做。
第一种办法,在框架中所有的基础类都是注册了门面模式的,所以在路由里边引入facade就可以进行代码追踪了。
但是既然都把门面模式的源码都看了怎么还会去使用第一种办法,肯定要把其中的一些小细节给扒出来。
在base文件中已经注册了门面的别名了,所以说在引入文件时可以使用use Config
,也可以使用use think\facade\Config;
这个时候就会来到thinkphp/library/think/facade/Config.php
这个文件。
可以看到是继承了门面类的。
来到Facade这个类中,拉到文件最后可以看到一个方法__callStatic
,这个方法是当调用不存在的静态的方法时就会执行这个方法。
最后就会去执行创建门面类的方法,最终会通过容器返回返回对应的实例,比如使用的是Config,最终就会返回Config的这类的实例。
最后就会回到开始,使用call_user_func_array
进行执行对应实例的方法。
static::createFacade()会返回Config的对应实例。
这一块内容就说到这里了,虽然说之前在门面中也提到了但是在这里在回顾一下也是很有必要的,为故而知新嘛!
通过定义路由再谈门面这一节中,就可以知道下图中的rule
方法会执行那个类的那个方法。
根据之前咔咔给大家介绍的方法就可以知道最终会执行到thinkphp/library/think/Route.php
这个文件中的rule
方法。
这里就会出现一个问题就是这个group
是什么,是怎么执行的,其实在上边的图已经描述的很明白了。
咔咔在用文字给大家在说一遍,可以对照着进行查看源码。
先看一下这个方法熟悉不熟悉。
没错这个方法在容器那一节中进行了特别的讲解,如果不明白的去前言查看之前的文章进行查看。
那么这个方法在哪里执行的,咔咔就直接说了,就不说的那么细了。
当使用Route::rule();时就会执行到门面的__callStatic方法。
这个方法已经说了好多次了,当执行的静态方法不存在时就会执行。
然后就会去执行createFacade这个方法。
在这个方法需要特别注意最后一行,也就是圈出来的哪一行代码。
这里需要注意一下static::class
,它返回的就是Route类,至于是怎么返回的之前也说过,如果不会的可以评论区见哈!
所以make方法的第一个参数就是Route。
接着就会进入到容器类的make方法,在这个方法中,注意咔咔圈的俩处。
在容器类中一定要注意的四个属性,咔咔给大家画了出来。
第一次进来会存入到容器标识名中。
并且第二次执行make方法时传的是标识名的值。
直到这里就会执行到咔咔圈的第二处,执行invokeClass这个方法。
来到invokeClass方法中。
在这个方法中主要使用的是反射的知识。
首先会把传过来的think\Route,进行反射类的实例化。
然后会去判断think\Route中是否存在__make方法。
最后就会去执行Route类的__make方法。
并且进行依赖注入App类和Config类。
同时进行了实例化了本类就是代码$route = new static($app, $config);
那么就会去执行构造函数。
接着来到构造函数的方法中查看。
这里一定要注意第二步的注释,这个已经说了很多次了。
如果有疑问就是为什么使用了ArrayAccess。
咔咔就给大家捋一下,首先App
类是继承的Container
类。
Container
类又继承着ArrayAccess
类,所以就可以使用像之前的说,像数组一样访问对象。
接着就会来到方法setDefaultDomain
。
这里需要注意一下咔咔圈的地方,在这一节的开头就使用的这个属性来执行的rule
中的addRule
方法。
这个group就是think\Route\Domain
这个类。
又因为think\Route\Domain
继承着think\Route\Group
所以会执行到think\Route\Group
到这个类里边。
这下所有的流程就都已经理顺了。
通过上面的这一顿分析和刨铣相信大家对这一块的内容就十分了解了。
接下来的内容就是对路由规则的处理方式进行解析。
这几个参数就对前俩个做一个简单的打印,然后看一下这俩个参数分别都是什么。
参数rule
参数$route
可以看到这俩个参数几个就是 路由的前半部分,一个是路由的后半部分。
从而就可以得知代码会执行到下图第一处圈起来的地方。
此时需要注意一点就是在上图中圈起来的第二处地方,这个地方会在什么时候执行呢!
就是当下图路由这样设置的时候才会执行那段代码。
这里的路由设置只是为了做演示,在实际工作中不能这样设置路由啊!第二个路由地址会把第一个路由地址给覆盖的。
接着代码就会执行到创建路由规则实例,也就是下图圈出来的地方。
关于创建路由规则实例的几个参数需要进行简单的介绍一下
第一个参数:$this->router
第二个参数:$this
,就是指的think\route\Domain
。
接下来的几个地址就是路由规则和地址,就没有必要看了,主要就是第一个参数。
接下来就需要进入到创建路由规则实例的方法中
代码就会追踪到thinkphp/library/think/route/RuleItem.php
这个类中。
在这个类中做的事情就是设置规则,也就是下图咔咔圈出来的地方。
路由规则预处理setRule
方法解读。
上图中最后执行的流程就会来到setRule这个方法。
这段代码没有我们眼看这那么容器阅读,接下来就跟着咔咔一步一步的去阅读这块代码。
1.首先代码就会执行这部分
从一开始就进行了一个简单的判断$,那么这个是从哪里过来的呢!
在文件thinkphp/library/think/route/RuleGroup.php
这里就对$进行了处理。
所以说在什么情况下会执行预处理的第一部分呢!
我们来看一下简单的案例。
然后在路由预处理中进行打印,就会发现打印结果后边会多一个$符号。
substr介绍
这里对substr进行简单的说明一下,碰到每一个知识点都简单的回顾一下。
这个方法用来字符串截取。
参数一:需要截取的字符串
参数二:从什么位置开始截取,正数从左往右,负数结