本文主要介绍框架的执行流程 如果不清楚框架是怎么执行的,那么看在多的代码都是只是认识代码而已,阅读源码是为了学习其框架的设计思想和代码模式。 而执行流程则是将我们学习的东西串联在一起,从而更好地理解。咔咔也会给大家把执行流程用思维导图的方式画出来。 只要大家在本文学习到一点点的知识点,咔咔也是心满意足的。 这个流程图只是针对initialize的执行过程,其余的执行过程后期会进行补充,都是以脑图的形式呈现给大家的。 这里的内容跟容器的内容有点重复,因为执行流程是从入口文件开始的,并且最后也是通过容器执行的。 然后就会进入到文件 来到initialize这个方法,先看上半部分。 这里有一个小的问题点给大家提出来,在初始化应用的这个方法里边存在这样一行代码。 有没有小伙伴对这个 如果你有疑惑那就跟着咔咔一起来看,没疑惑的就可以继续往下看了。 App这个类是继承的容器类,那么这个env和config不论是在app还是container类中都是没有这俩个属性的。 那么怎么就可以直接调用呢!而且代码追踪都会追踪到env类和container类中。 需要知道这个源头就需要我们去在大致的看一遍container类的代码。 经过一番苦读之后,可以看到下图的几行代码。这几行代码全部使用的是魔术方法。 当访问env类不存在的时候就会去执行make方法。 make这个方法在容器那一章节进行的细的不能再细的解读了。 这个make方法最终会返回一个类的实例,并且还会存到容器里边。 这里只放一个make方法的代码,如果有不会的可以去看之前的文章。 最后就是加载一系列的数据,加载详情请看前言的思维导图。 在阅读源码的过程中,有一个很难把控的问题就是一个方法在不同的地方进行了调用,但是咱们确一时半会根本不知道都在哪里调用了。 这里用init方法来做一个演示。 init方法是初始化应用或者模块的一个方法,但是这里的module参数确实一个空值。 打印的结果就是空,这就是一些新学习的伙伴会犯的一个错误,因为这个方法不可能只调用一次的。 如果初始化模块都是空那么这个方法就没有存在的必要了。 如果在不知道新的技巧之前,就会进行一系列的断点打印,看在哪里进行了执行,比如在这个init的上层去打印。 也就是在initialize那个方法里边去打印做断点,但是这样很是麻烦的,而且很有可能浪费了大量的时间还是找不到正确的地方。 小技巧之debug_backtrace() 这个方法会产生一条回溯追踪,会显示出一个方法所有的调用位置。 使用方式就是如下图,只需要把debug_backtrace这个方法打印出来即可。 根据得到的数据信息,就可以非常快的进行定位。 第一次就是在app类的215行。 第二次是在 可以在这里做一个打印,看一下这个module是否为index 上文给大家提供了一个小技巧 并且案例也是使用的init这个方法来演示的,因为接下来就是要对init这个方法进行深入的了解。 在init方法里边主要做的事情在上边的脑图已经描述的很清楚了。 这里附带上一份代码,可以对着代码看上边的执行流程,对每一步都做了简单的说明。 咔咔个人见解对源码进行优化 在设置模块的这步代码咔咔感觉不是很是严谨,因为init方法会在俩个地方进行执行。 第一次的模块为空,这块代码执行是没有任何意义的。 下面在对容器的对象实例进行配置更新时进行了一次判断,判断模块的这个参数是否为空,如果不为空才会执行。 那么同样的道理,咔咔感觉在设置模块路径这块也应该在这个判断里边。 虽说第二次执行会把第一次的结果覆盖掉,但是咔咔感觉下图这样使用才会更好。 在上一节中这里就是最后的内容,那这个对实例进行更新配置,到底更新了什么,怎么更新没有说明。 在这一小节中就会做出说明,同样可以配合着前言的思维导图看。 在这一节中咔咔感觉最重要的就是下图的内容了。 追踪方法Db::init() 追踪方法过来后可以看到就是对Db类中的config属性进行赋值,把database中的值赋值给Db类中的config属性。 来到中间件这个类里边,可以看到就是把本类的配置和传递过来的参数类进行合并,同样也是进行config属性的赋值。 跟上边案例的Db类的init方法实现的效果是一致的。 这里在提一嘴就是在 那么这是怎么可以进行执行的呢!是因为App类继承了容器类,容器类中有四个魔术方法,其中有一个__get方法,就是在获取不存在的属性时会执行那个方法。 在魔术方法__get方法中执行了一个make方法,这个make方法说了好多次了,这个方法最终会返回一个应用的实例,然后用这个实例调用对应实例类的方法。 这一块一定要理解好,阅读源码就是这个样子,我们需要对一切未知的进行的解决,只有这样才能提高我们的编程能力和思想。 本节会对调试模式做出简单的说明,并且会对框架代码冗余情况进行简单的提出。 没有人写的代码是没有漏洞的,如果有那就是你还没有达到一定的造诣。 调试模式 在第一节中只提到了initialize方法的上半部分,因为在这一节之前聊的都是关于应用初始化init的内容。 接下来会对这一块的内容进行简单的说明。 接下来的内容估计不是很好理解,都是平时在工作中根本使用不到的。 上边这三个先暂时认识就行,后期如果有机会会专门出一篇文章做解释的。 这里也仅仅代表咔咔个人的观点。 可以先看看这部分的代码,这俩处代码是不是很是熟悉,没错就是在上文的init方法中容器对象实例配置更新见到过。 本节主要是针对框架执行流程中的初始化应用做了简单的探讨。 至于在app类的run方法下面还有很多的执行过程在这一节中没有做过多的解释。 在阅读源码的过程中给大家提了一个很好得小技巧,那就是如何去查看一个方法都在哪里进行了执行。 这个方法为 这个方法在调试源码的过程中是非常有效的,一定要好好利用这个方法。 在就是对初始化应用init方法进行了特别详细的介绍。 其中咔咔感觉这块设计最好的就是在容器中的对象实例进行更新配置那一块,先读取所有的配置,然后在通过各个类的方法进行配置的设置。 这种代码规划和设计思路值得我们去学习。 最后聊到了调试模式和框架的代码冗余问题,关于调试模式这里咔咔给大家提个醒项目在线上的调试模式一定要关闭。 否则你的项目就类似于裸奔的存在,没有一点点的安全可言。 这块有点不好理解的就是对于缓冲区,关于这块的内容咔咔认为暂时没有必要去钻牛角尖,先认识认识然后在进行深入的研究。 缓冲区的这块内容估计工作了三四年的也很少有人使用,所以先认识,知道怎么一回事,咔咔后期学习了之后在给大家进行补充。 直到这里关于框架的执行流程之初始化应用就结束了,这一节没有过深需要学习的,主要是其中的代码设计模式和实现思路。 最后这个图大家一定要跟着源码看一看哈! 坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。
“
前言

一、框架执行流程之初始化应用的数据设置

thinkphp/library/think/App.php的run方法,在这个方法中主要就是下图框出来的地方,执行的initialize方法。
microtime(true);返回的是unix的微秒数memory_get_usage返回的是分配给PHP的内存量,单位为字节static::setInstance($this);这里是将app这个实例设置为容器实例$this->instance('app', $this);这个在之前容器章节就提到了,就是为了把app这个类绑定到容器里边去,也就是注册树模式。
$this->env和下边的$this->config这俩个调用有疑惑。



二、如何查看一个方法都在哪里执行了
先做一个断点查看一下相关的数据信息。
那么正确的断点方式应该是这个样子的。
此时就会有一个问题,这个init方法明显是被调用了俩次的,那么另一次调用的地方是在哪里呢!



thinkphp/library/think/route/dispatch/Module.php类的60行

所以说有了这个方法就可以非常快速地定位调用位置。
三、框架执行流程之初始化应用init分析
debug_backtrace实战演示了如何查看一个方法都在哪里执行的。
bindTo方法进行绑定注册的。env环境变量配置里边<span style="display: block; background: url(https://files.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 初始化应用或模块<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@access</span> public<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@param</span> string $module 模块名<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@return</span> void<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">public</span> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">function</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">init</span><span class="hljs-params" style="line-height: 26px;">($module = <span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span>)</span><br/> </span>{<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 定位模块目录</span><br/> $module = $module ? $module . DIRECTORY_SEPARATOR : <span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span>;<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 第一次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\<br/> * 第二次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\<br/> */</span><br/> $path = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->appPath . $module;<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载初始化文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">elseif</span> (is_file(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->runtimePath . $module . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->runtimePath . $module . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载行为扩展文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'tags.php'</span>)) {<br/> $tags = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'tags.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($tags)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->hook->import($tags);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载公共文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'common.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include_once</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'common.php'</span>;<br/> }<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span> == $module) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载系统助手函数</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->thinkPath . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'helper.php'</span>;<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载中间件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'middleware.php'</span>)) {<br/> $middleware = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'middleware.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($middleware)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->middleware->import($middleware);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 注册服务的容器对象实例</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'provider.php'</span>)) {<br/> $provider = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'provider.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($provider)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->bindTo($provider);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * $path : "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\"<br/> * "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\"<br/> */</span><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 自动读取配置文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_dir($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'config'</span>)) {<br/> $dir = $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'config'</span> . DIRECTORY_SEPARATOR;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">elseif</span> (is_dir(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configPath . $module)) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\config\</span><br/> $dir = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configPath . $module;<br/> }<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// scandir:以升序的方式读取目录中的文件</span><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 返回就是config目录中的所有文件</span><br/> $files = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>($dir) ? scandir($dir) : [];<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">foreach</span> ($files <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">as</span> $file) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * $this->configExt:配置文件的后缀<br/> * pathinfo返回的是文件后缀,关于pathinfo共有三个可选的参数PATHINFO_DIRNAME、PATHINFO_BASENAME、PATHINFO_EXTENSION,分别为只返回文件名,文件目录名,文件扩展<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-string" style="color: #98c379; line-height: 26px;">'.'</span> . pathinfo($file, PATHINFO_EXTENSION) === <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configExt) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 俩个参数分别为<br/> * 1.目录+config目录下的文件<br/> * 2.config目录下文件名<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));<br/> }<br/> }<br/> }<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->setModulePath($path);<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($module) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 对容器中的对象实例进行配置更新</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->containerConfigUpdate($module);<br/> }<br/> }<br/></code>
四、对容器中的对象实例进行更新配置
我们可以随意追踪一到俩个方法查看一下那边到底执行了什么方法。
追踪方法$this->middleware->setConfig()对容器中的对象实例进行更新配置这一幅图中可以看到紫色部分是在本类中没有引用的。
五、浅谈调试模式以及代码冗余
关于框架代码冗余
如图
这块也就是咔咔个人提出的见解,由于咔咔式针对5.1做的源码解读,不太了解新版版是否做出了改动。
六、总结
debug_backtrace,这个方法需要大家多使用几次就知道怎么使用了,因为在打印出来的结果中也存在很多无用的信息。
“
0
0
相关文章
thinkphp如何配置伪静态隐藏index.php
thinkphp数据库迁移和数据填充怎么用
thinkphp查询作用域(scope)如何简化查询
thinkphp session无法保存或跨控制器失效怎么办
thinkphp如何防止SQL注入和XSS攻击
相关标签:
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。
5
2026.03.04
2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!
12
2026.03.04
本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。
33
2026.03.03
本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。
25
2026.03.03
Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。
77
2026.02.28
Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。
60
2026.02.28
Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。
48
2026.02.28
本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。
26
2026.02.27
本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。
20
2026.02.27
热门下载
相关下载
精品课程
共12课时 | 0.7万人学习
共18课时 | 1.3万人学习
共11课时 | 0.7万人学习

