Home >PHP Framework >ThinkPHP >ThinkPHP framework execution process (with brain map)

ThinkPHP framework execution process (with brain map)

咔咔
咔咔Original
2020-11-06 11:38:315302browse

This article mainly introduces the execution process of the framework

Preface

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.

ThinkPHP framework execution process (with brain map)

Execution flow chart

##1. Initialization application data settings of the framework execution process

The content here is somewhat repetitive with the content of the container, because the execution process starts from the entry file and is finally executed through the container.

ThinkPHP framework execution process (with brain map)

Entry file

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.

ThinkPHP framework execution process (with brain map)

Coming to the initialize method, let’s look at the first half first.

  • microtime(true);Returns the number of microseconds in unix
  • memory_get_usage What is returned is the amount of memory allocated to PHP, in bytes
  • The next step is to set several paths of the framework
  • static::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.


ThinkPHP framework execution process (with brain map)

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.

ThinkPHP framework execution process (with brain map)

Solution to doubts, why it can be used like this

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.

ThinkPHP framework execution process (with brain map)

Only put the code of one make method here. If you don’t know how to do it, you can read the previous article.

ThinkPHP framework execution process (with brain map)

The last step is to load a series of data. Please see the mind map in the preface for loading details.

ThinkPHP framework execution process (with brain map)

Execute loading

2. How to check where a method is executed

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.

ThinkPHP framework execution process (with brain map)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.

ThinkPHP framework execution process (with brain map)1ThinkPHP framework execution process (with brain map)Then the correct breakpoint method should be like this.

1ThinkPHP framework execution process (with brain map)1ThinkPHP framework execution process (with brain map)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.

1ThinkPHP framework execution process (with brain map)1ThinkPHP framework execution process (with brain map)1ThinkPHP framework execution process (with brain map)

Based on the obtained data information, positioning can be carried out very quickly.

The first time is in line 215 of the app class.

1ThinkPHP framework execution process (with brain map)


The first place where init is called

The second time is in the thinkphp/library/think/route/dispatch/Module.php class Line 60

1ThinkPHP framework execution process (with brain map)

The second call place

You can make a print here to see if this module is index

1ThinkPHP framework execution process (with brain map)ThinkPHP framework execution process (with brain map)So with this method, you can locate the calling location very quickly.

3. Initialization application init analysis of the framework execution process

The above provides you with a little trickdebug_backtraceA 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.

  • The positioning of the module from the beginning is the call to the init method in the second section, which will pass in the corresponding module
  • to load The tags file in the app directory contains files that define extended behaviors. The hook execution defined in the previous facade article is set in this file.
  • Load common files, which are public files, so public files are loaded here.
  • Load the helper function file helper. There is a method that everyone is very familiar with in the helper function, that is dump. This is why an error will be reported when using dump in some places.
  • Load the middleware file. What is given here is to directly load the middleware file in the app directory, but in the framework we need to define a directory as http. In this directory Define the middleware file below.
  • Register the container object instance of the service. The registration here uses the bindTo method in the container class for binding registration.
  • Read the configuration file. This section has been explained in depth in the section on loading the configuration file and will not be mentioned here. The configuration file will be read from two places: one is the config file under the first step module, and the other is the configuration file under the config directory.
  • Set the module path, and the module obtained in the first step will be envEnvironment variable configuration inside
  • Finally The first step is to update the configuration of the object instance in the container. The specific updates will be explained in detail later.
<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;">&#39;&#39;</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;">&#39;&#39;</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;">&#39;init.php&#39;</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;">&#39;init.php&#39;</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;">&#39;init.php&#39;</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;">&#39;init.php&#39;</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;">&#39;tags.php&#39;</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;">&#39;tags.php&#39;</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;">&#39;common.php&#39;</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;">&#39;common.php&#39;</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;">&#39;&#39;</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;">&#39;helper.php&#39;</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;">&#39;middleware.php&#39;</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;">&#39;middleware.php&#39;</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;">&#39;provider.php&#39;</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;">&#39;provider.php&#39;</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;">&#39;config&#39;</span>)) {<br/>                $dir = $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">&#39;config&#39;</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;">&#39;.&#39;</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.

2ThinkPHP framework execution process (with brain map)


Kaka’s suggestions for source code modification

4. Object instances in the container Update configuration

#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.

  • First, all the configuration information in the config directory will be obtained
  • The exception handling class will be registered from the app configuration file
  • The third block is to register and configure all the configuration information obtained in the first step to the corresponding class.
  • The fourth step is to load the corresponding language package after determining the module. The language package function can realize multi-language functions. Kaka has written an article before to realize multi-language functions. , if you are interested, you can check it out.
  • The last step is to process the cache based on the three attributes in the app configuration file

In this section, Kaka feels the most important The content is as shown in the picture below.

2ThinkPHP framework execution process (with brain map)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.

2ThinkPHP framework execution process (with brain map)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.

So how can this be executed! It's because the App class inherits the container class. There are four magic methods in the container class, one of which is the __get method, which is the method that will be executed when obtaining non-existent attributes.

A make method is executed in the magic method __get method. This make method has been mentioned many times. This method will eventually return an instance of the application, and then use this instance to call the method of the corresponding instance class.

This part must be understood well. Reading the source code is like this. We need to solve all the unknowns. Only in this way can we improve our programming abilities and ideas.

2ThinkPHP framework execution process (with brain map)


Middleware settings and configuration

5. Brief discussion on debugging mode And code redundancy

#This section will give a brief explanation of the debugging mode, and briefly raise the redundancy of the framework code.

No one writes code without loopholes. If there are, then you have not reached a certain level.

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.

  • Get the app_debug configuration item from the app configuration file
  • Set the debug level to the environment variable
  • When the debug in the framework is turned off, the ini_set method will be executed. This method is to assign a value to a configuration option.
The following content is probably not easy to understand, and it is not used at all in daily work.

  • ob_get_level: Returns the nesting level of the output buffering mechanism, so how to understand it! In fact, it will return 0 when the buffer area is inactive.
  • ob_get_clean: This function will return the contents of the output buffer and terminate the output buffer. Returns false if the buffer has no valid content. Essentially, it is equivalent to executing ob_getcontens() and ob_end_clean() at the same time.
  • ob_start: Turn on the output control buffer

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.

2ThinkPHP framework execution process (with brain map)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.

2ThinkPHP framework execution process (with brain map)As shown in the picture

2ThinkPHP framework execution process (with brain map)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.

6. Summary

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!

ThinkPHP framework execution process (with brain map)

Insert picture description here
"

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn