PHP8.1.21版本已发布
vue8.1.21版本已发布
jquery8.1.21版本已发布

ThinkPHP路由地址是怎么进行控制器实例化的

咔咔
咔咔 原创
2020-12-29 11:14:33 1754浏览

一、执行控制器中的方法

本文的请求地址为配置的域名。

image.png

通过上文可以知道$instance的值就是app\index\controller\Index的实例。

这块也是存在中间件的概念,依然如此中间件会在后文中单独提到,这里不做解释。

在这里$this->app['middleware']->controller这段代码的使用,还能记得是使用的ArrayAccess还是直接为__get吗?

这里是在使用访问数组的形式访问对象,所以使用的是ArrayAccess的形式,这俩种概念一定要区分清楚。

image.png

接下来就会执行获取方法名,至于这个方法名怎么获取的是在本类的init方法执行的,这里只需要知道返回的是index即可。

在这里需要注意的就是这行代码$this->rule->getConfig('action_suffix'),这里获取的是操作方法后缀。

image.png

假如现在给这个操作方法后缀设置一个值会变成什么样子呢!

给添加一个kaka的值,进行访问一下看会是什么结果。

image.png

这个时候进行访问会提示indexkaka的这个方法不存在,是不是清晰可见了,说明这个参数是在为所有的方法名追加一个kaka。

image.png

对获取当前操作名的代码进行扩展完成之后,紧接着就是if (is_callable([$instance, $action])) {,在这里可以看见我们的老朋友is_callable

对于这里的is_callable俩个参数通过上文都知道是什么了,第一个参数为app\index\controller\Index的实例,第二个参数为index执行操作方法。

那么is_callable的作用就是检测在app\index\controller\Index类中的index方法名是否可以执行。

很明显这里会返回一个true,因为在index类里边存在index方法的。

这里在做测试之前一定要把刚刚在app的配置文件中配置的方法名后缀那个给取消掉。

通过这个is_callable判断会存在三种情况,接下来咔咔将会从三个方面给大家进行解析。

第一种情况:类里边存在可执行的方法

  • 首先返回一个 ReflectionMethod 类
  • 获取方法名 index
  • 未设置方法名后缀返回空
  • 设置当前的操作名
  • 在这个案例中没有设置参数,所以最终的$vars就是一个空数组。

为了测试带有参数的这一段代码,我们需要对路由地址进行一点改动。

image.png

在之前没有使用路由,而是直接使用的默认地址,接下来将使用这个路由地址

image.png

使用这个路由地址进行一下数据的打印,可以看到就是我们设置的路由参数。

image.png

这段获取请求变量的方法会进入到$this->request->param();这行代码

框架是如何获取参数的

访问地址:http://www.source.com/index.php/hello/hello

在上文知道是通过$this->request->param()来获取参数的,那么在框架是如何获取参数的呢!

根据流程代码会执行到下图,根据获取的请求方式来使用对应的方式来获取参数,在这里需要明确的是我们使用的是get请求。

所以代码会执行到$this->param,当前请求参数和URL地址中的参数合并这里,在这里注意咔咔圈出来的地方。

由于咔咔是使用路由方式进行的请求所以,在这里框架专门为路由封装了一个获取请求参数。

image.png

来到这个route方法,看到注释就明白是用来获取路由参数的,但是还是需要在进入一层到input。

image.png

在之前路由的那一期文章中在获取到路由参数的时候会把参数合并到request的route属性。

image.png

所以说$this->route就是存放的这条路由规则所有的参数,包含路由参数。

image.png

这时执行流程会执行到获取变量 支持过滤和默认值,在上文中$this->route穿进来的参数是false,所以说这块会直接返回。

image.png

这里返回的结果会返回给上文我们开始解析的地方,也就是说这个$vars就是获取到的路由参数。

image.png

第二种情况:类里边不存在可执行的方法

当第一种判断执行is_callable判断类里边的方法不可执行时,就会执行到第二种情况。

image.png

先来请求的一个没有设置的路由地址,看会返回什么。

image.png

根据代码给的提示,我们来到index控制器建立一个_empty方法,然后在来请求一次,看一下会发生什么。

image.png

根据打印结果就可以看出来当访问的方法不存在时就会去执行_empty这个方法。

image.png

那么这个方法是怎么执行的呢!这种执行方式就是利用反射机制来实现的,关于反射咔咔之前专门出了一篇文章来讲解的,但是大家还是需要对着文档进行阅读查看。

第三种情况:类里边不存在可执行的方法也不存在_empty方法

这种情况就比较简单了,就是直接返回错误信息,关于这里异常处理咔咔也会在后文说到。

image.png

三种情况执行完

三种情况分析完了,最后都会去执行统计的方法。

调用反射执行类的方法 支持参数绑定,也就说这里的闭包执行流程到这里就执行完了。

关于后边的自动请求,在第五节中详细说明。

image.png

二、路由地址是怎么进行控制器实例化的

在上一节中我们对路由进行了三四期的讲解,最终讲解的位置就路由调度,那么设置的路由是如何执行呢!

接下来使用这个路由作为案例

image.png

还记得在开始进行路由检测时的返回值是什么吗?请看下图

image.png

image.png

当时没有对接下里的代码进行详解,直接说明了实例化控制器,现在要说的就是记录当前调度信息这行代码。

在这里$this->request是使用的当访问不存在的属性时会去执行容器类的魔术方法,最后通过容器返回一个实例。

所以说代码会执行到下图位置,设置或者获取当前请求的调度信息

image.png

通过在控制器实例化这里进行打印会发现在这里的返回的值是index,这个值是在控制器进行设置的,接下来来到控制器进行查看一下。

image.png

来到init方法对result做打印查看结果,使用的是路由地址

image.png

image.png

image.png

你知道到为什么这里的值发生改变了吗?

在上文打印出来的值为下图,为什么在这里就是上图的呢!

image.png

在路由那一节中最后一步就是发起路由调度,最后调用了一个路由到模块/控制器/操作这个方法。

image.png

这个方法dispatchModule最后也是实例化一个类,接下来需要对这个类进行深究

image.png

根据代码追踪可以看到其实就是think\route\dispatch\Module这个类

image.png

来到Module这个类,又会发现继承着Dispatch

image.png

<a style="color:#f60; text-decoration:underline;" href="https://m.php.cn/zt/15717.html" target="_blank">thinkphp</a>/library/think/route/Dispatch.php这个类的控制器中,会发现对dispatch这个变量进行了设置。

image.png

这个时候回头在看一下路由到模块/控制器/操作这里的方法传入的参数是什么,哈哈

image.png

所以说最终的值就是刚刚打印的只是单独的数组形式的。

image.png

那么接下来的动作就跟不使用路由访问的流程一样的,就不用在进行解析了。

直到这里关于路由地址是怎么进行控制器实例化的就结束了。

关于给$this->app->controller传入的是index,返回的是整个类名,具体的实现过程就不去解析了,实现的方法是$this->parseModuleAndClass,可以自行进行研究哈!

三、执行autoResponse调度

在第四节中只提到了执行控制器中的方法是从下图的地方进行返回的,但是怎么返回的没有进行详解。

接下里会用一丢丢的时间来说一下是如何执行的。

image.png

访问路由地址为下图,可以看到返回的数据就是控制器中需要返回的数据。

image.png

image.png

打印的值是下图地方,这里就需要明确哈!源码阅读就是这样需要一点点的进行摸索,时间长了就对其中的东西就明白了。

image.png

接下来就对$this->autoResponse($data);这个方法进行深入的解析,这个方法按照字面意思就是自动响应。

image.png

在这个执行流程的第一行中$data instanceof Response,对这个不了解接下来就没办法阅读了。

不会和不明白的还是需要去解决的,阅读源码就这样,一点点的攻克才能获得胜利。

关于instanceof的使用

instanceof可以判断某个对象是否是某个类的实例,判断一个对象是否实现了某个接口。

接下来咔咔针对这个做一个简单的实例给大家演示一下,就明白这个是怎么回事了。

案例一

首先建立俩个类,案例如下图。

image.png

下图就是打印结果,可以看到第一个返回true,第二个返回false。

判断某个对象是否是某个类的实例,也就是说$instance就是类Test的实例,所以会返回true。

image.png

案例二

案例二跟案例一是不同的,建立了一个接口,然后类实现接口的案例。

image.png

最终返回结果全是true,也就是说如果一个类实现了另一个接口,那么在判断时都会是true。

image.png

以上就是针对instanceof给出的俩种演示案例,对其理解就是判断一个实例是否为某个类的实例。

那么就在回到正文,$data instanceof Response这行代码肯定不会成立,因为data传过来的就是控制器返回的值。

所以说代码执行流程会执行到下图位置,使用了is_null函数来做判断,判断肯定为false,所以会执行以下的代码。

在这块代码中前俩个点就不去解析了。

第一个就是默认自动识别响应输出类型,这里就是在判断是否为ajax请求,具体实现方法等咔咔这次把框架源码解析完之后,然后每天会抽一点时间,对框架的一些方法进行一点点的剖析。

第二处位置就是在配置文件获取对应的配置信息,看的是执行的rule类的方法,但是在方法中是执行的获取配置信息的代码。

image.png

接下就需要对上文没提到的第三处进行解析了,也就是代码$response = Response::create($data, $type);

来到类thinkphp/library/think/Response.php的方法create中,这个方法就是用来创建Response对象。

这里只需要去关注一下咔咔圈出来的地方即可,在thinkphp/library/think/response这个目录下是不存在html的。

所以代码会直接去实例化本类,然后进行返回。

image.png

来到本类的构造函数就主要做一下几件事情。

  • 将返回值赋给本类的data属性
  • 设置页面输出类型
  • 返回状态码
  • 设置app实例对象
  • 头部信息

image.png

然后代码会将返回值赋值给autoResponse这个方法的$response这个变量。

最后就是将这个$response给返回出去,并且返回信息如下图打印结果。

image.png

image.png

然后代码依然会向上层返回,回到最初的闭包函数。

在咔咔圈出来的地方,下一行代码也是关于中间件,只需要知道最终返回结果跟上图打印的结果一样即可。

image.png

最终返回结果回到thinkphp/library/think/route/Dispatch.php,咱们也就是从这里开始的解析的。

image.png

将返回的结果返回给$data,然后在进行执行return $this->autoResponse($data);

你没看错,这里的代码熟悉吧!

这个时候返回的结果就是Response的实例,所以会直接返回$response

image.png

直到这里关于执行控制器中的方法,并且响应就都解析完了。

不轮是设置的路由规则,还是直接使用模块控制器方法的方式访问最终都会通过上文的方式进行返回响应结果。

坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。