“本文会对控制器最后的执行流程和使用的俩个高级属性进行简单的学习,一个是fastcgi_finish_request方法巧用,另一个是trait特性,超类的概念多少都有过了解,接下来一起来解析一下。
”
当执行完控制器中的方法响应数据给App类的run方法,直到这里就已经执行完了。
是不是有点懵这里的数据最终会返回哪里呢!
之前写过的框架执行流程、路由、控制器实例化都是从这里开始进入的。
所以当run方法执行完成之后,就会把对应的结果给返回到这里。
这一部分的代码Container::get('app')
应该都知道了是返回一个App类的实例。
然后通过App类去执行run方法,才会有之前讲过的一切。
下图是咔咔从半中腰做的一个思维导图,前面的没有,后边的所有知识点都会写在这个思维导图里。
执行完run方法就会去执行Container::get('app')->run()->send()
send这个方法,有多少人会认为在App类里边执行send方法。
其实不是的,回想一下之前执行控制器方法然后返回的响应结果是什么?
如果你不是很粗略的看都会记得是Response的一个对象实例。
所以说send方法会去response类里边去执行。
先不看其它的,先看这行代码$this->app['hook']
,现在知道是执行的那里吗?
这种形式就是通过访问数组形式去访问对象的属性,也就是之前解析的ArrayAccess这个类。当访问的属性不存在时会去执行offsetGet,然后执行魔术方法__get,最终通过make方法返回实例,这一切的操作都是在容器中。
对这行代码具体是监听的什么就不去做解析了。
接着需要看处理输出数据的这行代码$data = $this->getContent();
这个方法做的事情就是将传过来的数据赋值给本类的content属性。
其实在获取输出数据这个方法中,请看咔咔圈出来的第一个地方感觉是很没有必要。
可以看到根本对数据就没有任何的处理,只是简单的返回了,所以说框架有好的地方也有不好的地方,只有你去阅读了才会知道,否则你会对你经常使用的工具一无所知。
在接着就是Trace调试注入,就是通过配置文件配置的,通过调用debug类实现的,这里就不详解了。
然后就是缓存判断,缓存会在后文中单独拎出来讲,所以也是过。
在接下来就对响应头的设置了,检测 HTTP 头是否已经发送,这块的东西就很重要了,也是平时接触不多的知识点了。
最后一步,来了来了,它来了,它带着echo来了,执行了一个方法$this->sendData($data);
给人一种媳妇熬成娘的感觉,终于来到的终点站,一个echo输出了咔咔几十天的心酸啊!
为了到达这个echo咔咔是经历九九八十一难啊!战斗还未停止,同志仍需努力啊!
那么到这里关于框架执行然后到应用初始化,在到路由检测、控制器的实例化、然后返回response实例,在通过入口文件执行send方法。
最后将数据输出到终端,也就是一个echo的事情。
虽然这里的战斗结束了,但是在下面还有一个非常重要的知识点,咔咔将重新提一节来进行说明。
在上一节中通过Container::get('app')->run()->send();
在response类中执行了send方法,输出了数据。
但是在输出数据之后还执行了一个方法fastcgi_finish_request();
,给的注释是提高页面响应,接下来好好来扒一扒其中的奥秘。
在PHP官网中看到这样一段话
The script will still occupy a FPM process after fastcgi_finish_request(). So using it excessively for long running tasks may occupy all your FPM threads up to pm.max_children. This will lead to gateway errors on the webserver.
在fastcgi_finish_request()之后,脚本仍将占用FPM进程。 因此,对于长时间运行的任务过度使用它可能会占用您的所有FPM线程,直到pm.max_children。 这将导致Web服务器上的网关错误。
所以说在没有彻底的了解这个方法之前不要轻易的在自己的项目中使用这个方法。
接下来咔咔将使用一个案例来演示这个方法的使用,仅仅只是演示使用,如果需要使用到项目中请仔细阅读文档应该注意的问题。
案例演示
公司有一个业务需要发送通知给用户,但是由于发送时间太久,非常费时间,有可能需要好几十秒的时间,更严重的会直接导致浏览器连接超时。
在一个问题就是用户体验的问题,用户等待时间过程,体验当然不好。
为了解决以上俩个问题,今天谈论的fastcgi_finish_request
就派上了用场。
理解
对这个函数的理解其实就是发送响应给浏览器,用户等待时间大大缩短,但是PHP进程还是在运行的。
这样就达到了来个目的,就类似于我们经常说的异步执行。
直观的来说就是发送邮件有可能需要10秒,但是用户是没有感知的,用户点击发送邮件之后直接就返回发送成功,浏览器响应结束,用户做其它事情,后台进程继续执行发送邮件的任务。
案例
具体代码
<span style="display: block; background: url("https://files.mdnice.com/point.png") 10px 10px / 40px no-repeat rgb(40, 44, 52); height: 30px; width: 444.812px; margin-bottom: -7px; border-radius: 5px;"></span><code class="hljs" style="overflow-x: auto; padding: 15px 16px 16px; color: rgb(171, 178, 191); display: -webkit-box; font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace; font-size: 12px; background: rgb(40, 44, 52); border-radius: 5px;"><span class="hljs-meta" style="color: rgb(97, 174, 238); line-height: 26px;"><?php</span><br/><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br/> * 设置超时时间,变成不限制<br/> *<br/> */</span><br/>set_time_limit(<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">0</span>);<br/><br/><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br/> * 本函数模拟非常耗时的任务,执行完毕需要5秒的时间<br/> */</span><br/><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">function</span> <span class="hljs-title" style="color: rgb(97, 174, 238); line-height: 26px;">writeFile</span><span class="hljs-params" style="line-height: 26px;">()</span><br/></span>{<br/> $path = <span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'D:/phpstudy_pro/WWW/kaka.txt'</span>;<br/> file_put_contents($path,<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'程序运行开始'</span> . PHP_EOL,FILE_APPEND);<br/> <span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">for</span>($i =<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">0</span>;$i < <span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">5</span>;$i++) {<br/> file_put_contents($path,time() . PHP_EOL,FILE_APPEND);<br/> sleep(<span class="hljs-number" style="color: rgb(209, 154, 102); line-height: 26px;">1</span>);<br/> }<br/><br/> file_put_contents($path,<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'程序运行结束'</span> . PHP_EOL,FILE_APPEND);<br/><br/>}<br/><br/><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br/> * 输出文字标记,任务开始<br/> */</span><br/><span class="hljs-keyword" style="color: rgb(198, 120, 221); line-height: 26px;">echo</span>(<span class="hljs-string" style="color: rgb(152, 195, 121); line-height: 26px;">'任务开始'</span>);<br/><br/><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br/> * 后台执行非常耗时的任务<br/> */</span><br/>register_shutdown_function(writeFile);<br/><br/><span class="hljs-comment" style="color: rgb(92, 99, 112); font-style: italic; line-height: 26px;">/**<br/> * 立即发送请求<br/> */</span><br/>fastcgi_finish_request();<br/><br/><br/><br/></code>
以上测试全部使用linux系统进行测试哈,否则你看不到直观的效果。
经过上面的演示,响应非常快,浏览器响应结束后,后台程序依然进行执行每秒执行一个时间戳。
以上就是对fastcgi_finish_request
方法的简单介绍,如果你也感兴趣可以进行简单的尝试一下,有助于更好的去理解其中的小秘密。
应该在俩年前咔咔就对这个特性进行过一次解析,trait
就是常说的超类。
这个特性是在PHP5.4才加入的,这个特性不是经常使用的接口更不是类。
这个特性是为了解决PHP的一大弱点只能单继承的缺点,但是也不能叫多继承,严谨一点的就是类似多继承的功能而已。
接下来给大家演示一个案例。
创建test文件一,并且返回对应类名。
创建test1文件,并且返回对应类名
创建控制器文件用来输出信息。
然后在控制器中引入对应的超类文件,这里需要注意的是圈住的第一个框,这个框就是直接引入超类test文件。
然后可以直接进行访问,看会返回什么。
通过上图访问结果结果可以看得到返回的是Test超类文件的方法,但是此控制器同样也基础了Controller控制器,这也就是在文章一开头就说的超类就是实现了一种多继承的功能而已。
但是这里会存在一个问题,请看下图报错信息。
上图的报错信息是因为在控制器中使用了俩个超类导致的,也就是下图的使用方式。
那么如何解决这种报错信息呢!接下来跟这咔咔的节奏一起来。
解决报错信息
在解决之前问题之前得先清楚这个问题是由于什么引起的。
出现这个错误的原因是引用的两个trait里面有同名的hello函数,出现了冲突。
但是在日常开发中这种情况都是可以避免的,因为手动改方法名还是很方便的,但是这里咔咔教大家如何解决这种问题。
一是用其中一个trait里的hello方法覆盖另外一个trait的同名方法,因为两个方法内容是一致的,所以我这里直接选择insteadof覆盖;
二是给他们用as起别名,这样就不会有冲突了。as关键词还有另外一个用途,那就是修改方法的访问控制。
经过上图的改动之后,再一次的进行访问,看一下返回结果。
那么这个时候就会有伙伴有疑问了,就是案例打印结果一直是Test类的方法,Test1类的方法一直没有进行打印。
那是如何进行访问的呢!来接着看一下。
从上图可以看到将访问方法改为了别名控制访问,接着来看一下访问结果。
从上图中可以可以看到返回结果就是超类Test1类的返回结果。
那么关于as这个的使用就需要大家在去搜索一下使用方式,有时候注意一下细节就可以学到很多知识点。
直到这里关于控制器的源码解析就到这了,咔咔通过源码给大家分析控制器的如如何进行实例化的。
也再一次的进行了对ArrayAccess和魔术方法的调用关系,一定要有自己的思考去想问题。
在就是对访问控制器后是如何进行响应数据的,等等。
也在源码中学到了关于fastcgi_finish_request方法巧用,但是在使用这个函数一定要注意关于咔咔提到的俩个注意点。
最后就是对超类的一个简单案例描述。
“坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。
”
以上是ThinkPHP框架使用的特性fastcgi_finish_request和trait的详细内容。更多信息请关注PHP中文网其他相关文章!