“This article mainly introduces the execution process of the framework
”
If you don’t know how the framework is executed, then most of the code is just to understand the code. Reading the source code is to learn the design ideas and code patterns of the framework.
The execution process is to connect the things we learn together to understand better. Kaka will also draw the execution process for you in the form of a mind map.
As long as everyone learns a little bit of knowledge from this article, Kaka will be satisfied.
This flow chart is only for the execution process of initialize. The rest of the execution process will be supplemented later and are presented to everyone in the form of a mind map.
Then you will enter the run method of the file thinkphp/library/think/App.php
. In this method, the main picture is as follows Where the box is drawn, the initialize method is executed.
Coming to the initialize method, let’s look at the first half first.
microtime(true);
Returns the number of microseconds in unixmemory_get_usage
What is returned is the amount of memory allocated to PHP, in bytesstatic::setInstance($this);
This is to set the app instance as a container instance$this->instance('app' , $this);
This was mentioned in the previous container chapter, in order to bind the app class to the container, which is the registration tree mode. There is a small problem here for everyone. It exists in this method of initializing the application. Such a line of code.
Does anyone have any doubts about the two calls $this->env
and the following $this->config
.
If you have any doubts, just follow Kaka and read it. If you have no doubts, you can continue reading.
The App class is an inherited container class, so the env and config do not have these two attributes in either the app or the container class.
Then how can it be called directly? And code tracking will be traced to the env class and container class.
To know this source, we need to take a rough look at the code of the container class.
After some hard reading, you can see a few lines of code in the picture below . These lines of code all use magic methods.
When the accessed env class does not exist, the make method will be executed.
The make method is so detailed in the container chapter that it cannot be explained in detail.
This make method will eventually return an instance of the class and will be stored in the container.
Only put the code of one make method here. If you don’t know how to do it, you can read the previous article.
The last step is to load a series of data. Please see the mind map in the preface for loading details.
In the process of reading the source code, one problem that is difficult to control is that a method is called in different places, but we do not know it at all for a while. Where is it called.
Here is a demonstration using the init method.
The init method is a method to initialize an application or module, but the module parameter here does have a null value.
First make a breakpoint to view the relevant data information.
The printed result is empty. This is a mistake that some new learning partners will make, because this method cannot be called only once.
If the initialization modules are all empty, then there is no need for this method to exist.
Then the correct breakpoint method should be like this.
There will be a problem at this time. This init method is obviously called twice, so where is the other call!
If you don't know the new technique, you will print a series of breakpoints to see where the execution is performed, such as printing at the upper level of the init.
That is to say, print breakpoints in the initialize method, but this is very troublesome, and it is likely to waste a lot of time and still not find the correct place.
Tips: debug_backtrace()
This method will generate a backtrace, which will show all the calling locations of a method.
The usage is as shown below. You only need to print out the debug_backtrace method.
Based on the obtained data information, positioning can be carried out very quickly.
The first time is in line 215 of the app class.
The second time is in the thinkphp/library/think/route/dispatch/Module.php
class Line 60
You can make a print here to see if this module is index
So with this method, you can locate the calling location very quickly.
The above provides you with a little trickdebug_backtrace
A practical demonstration of how to view where a method is executed.
And the case also uses the init method to demonstrate, because the next step is to have an in-depth understanding of the init method.
The main things done in the init method have been clearly described in the mind map above.
bindTo
method in the container class for binding registration. env
Environment variable configuration inside<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>
The previous code is attached here. You can look at the code to see the execution process above, and each step is briefly explained.
Kaka’s personal opinion to optimize the source code
Kaka doesn’t feel very rigorous in the step of setting up the module, because the init method will be carried out in two places implement.
The first time the module is empty, it is meaningless to execute this code.
The following is a judgment made when updating the configuration of the object instance of the container to determine whether the parameter of the module is empty. If it is not empty, it will be executed.
For the same reason, Kaka feels that setting the module path should also be included in this judgment.
Although the second execution will overwrite the first result, Kaka feels that it will be better to use it like the picture below.
#In the previous section, here is the final content. Then, when updating the configuration of the instance, there is no explanation of what is updated and how to update it.
Explanations will be made in this section, which can also be read in conjunction with the mind map in the preface.
In this section, Kaka feels the most important The content is as shown in the picture below.
We can trace one or two methods at will to see what methods are executed there.
Tracking method Db::init()
After tracking the method, you can see that it assigns the config attribute in the Db class and assigns the value in the database Give the config attribute in the Db class.
Tracking method $this->middleware->setConfig()
Coming to the middleware class, you can see that this class The configuration is merged with the passed parameter class, and the value of the config attribute is also assigned.
The effect achieved by the init method of the Db class in the above case is consistent.
What I want to mention here is to update the configuration of the object instance in the containerYou can see in this picture that the purple part is not referenced in this class.
Debug mode
Only the first half of the initialize method is mentioned in the first section, because before this section all the talk was about application initialization init content. The content of this section will be briefly explained next.It’s enough to get to know the above three for now. If there is a chance, I will write an article about it later. explained.
About framework code redundancy
This only represents Kaka’s personal opinion.
You can take a look at this part of the code first. Are these two codes very familiar? Yes, you have seen it in the container object instance configuration update in the init method above.
As shown in the picture
This is Kaka’s personal opinion. Due to Kaka’s source code interpretation for 5.1, I don’t know whether the new version has made it. changed.
This section mainly discusses the initialization application in the framework execution process. .
As for the many execution processes under the run method of the app class, there is not much explanation in this section.
In the process of reading the source code, I gave you a good tip, that is, how to check where a method is executed.
This method is debug_backtrace
. This method requires you to use it a few times before you know how to use it, because there is also a lot of useless information in the printed results.
This method is very effective in the process of debugging source code. Be sure to make good use of this method.
This is a particularly detailed introduction to the init method of initializing the application.
Among them, Kaka feels that the best part of this design is to update the configuration of the object instance in the container. First, read all the configurations, and then set the configuration through the methods of each class.
This kind of code planning and design ideas is worth learning.
Finally, we talked about the code redundancy issue of debugging mode and framework. Regarding the debugging mode, Kaka would like to remind everyone that the debugging mode of the project online must be turned off.
Otherwise, your project will be like running naked, without any safety at all.
What is a bit difficult to understand is the buffer zone. Kaka believes that there is no need to dig into the details of this content for the time being. We should first understand it and then conduct in-depth research.
This part of the buffer is estimated to be rarely used by people who have been working for three or four years, so first get to know it and know what it is about. After Kaka learns it later, I will supplement it for everyone.
This is the end of the initial application of the execution process of the framework. There is nothing too in-depth to learn in this section, mainly the code design patterns and implementation ideas.
For this last picture, you must follow the source code and take a look!
"Keep learning, keep blogging, keep Sharing is the belief that Kaka has always upheld since he started working in the industry. I hope that Kaka’s articles on the huge Internet can bring you a little help. I am Kaka, see you in the next issue.
”
The above is the detailed content of ThinkPHP framework execution process (with brain map). For more information, please follow other related articles on the PHP Chinese website!