当前位置:网站首页>Source code analysis of ThinkPHP framework execution process

Source code analysis of ThinkPHP framework execution process

2020-11-09 10:49:00 Click-

This paper mainly introduces the implementation process of the framework

Preface

If you don't know how the framework works , So, in many codes, it's just to know the code , Reading the source code is to learn the design ideas and code patterns of its framework .

And the execution process is to link the things we learn together , To better understand . Kaka will also show you the execution process in the way of mind map .

As long as you learn a little bit of knowledge in this article , Kaka is also contented .

This flow chart is only for initialize Implementation process of , The rest of the execution process will be supplemented later , It's all presented in the form of brain maps .

 Insert picture description here
Insert picture description here

One 、 The data setting of initialization application of framework execution process

The content here is a little bit similar to that of the container , Because the execution process starts from the entry file , And finally, it's done through the container .

 Entrance file
Entrance file

And then it goes to the file thinkphp/library/think/App.php Of run Method , In this method, the main part is the following box , Executive initialize Method .

thinkphp/library/think/App.php Came to initialize This method , Let's look at the first half .

  • microtime(true); The return is unix Microseconds of
  • memory_get_usage The return is assigned to PHP Of memory , The unit is byte
  • Next, set up several paths of the framework
  • static::setInstance($this); Here is the general app This instance is set to the container instance
  • $this->instance('app', $this); This was mentioned in the previous chapter on containers , Just to put app This class is bound to the container , That's the registration tree model .

 Initialize the first half of the application Here is a small question for you to raise , In the method of initializing the application, there is such a line of code .

There's no partner for this $this->env At the bottom of the and $this->config These two calls have doubts .

If you're in doubt, follow Kaka , If you don't have any doubts, you can continue to look down .

App This class is an inherited container class , So this env and config Whether in app still container Class does not have these two properties .

So how can I call it directly ! And code tracking will trace back to env Classes and container Class .

We need to know the source and we need to go over it container Class code .

 Solve doubts , Why can I use it like this
Solve doubts , Why can I use it like this

After a hard study , You can see a few lines of code below . These lines of code are all magic .

When accessing env When the class does not exist make Method .

make This method can't be interpreted in detail in the chapter of container .

This make Method will eventually return an instance of a class , And it will be stored in the container .

 Magic methods in container classes There's only one make Method code , If there is not, you can read the previous article .

 Container class make Method Finally, load a series of data , Please refer to the mind map in the preface for loading details .

 Execute load
Execute load

Two 、 How to see where a method is executed

In the process of reading the source code , One problem that is hard to control is that a method is called in different places , But we really don't know where to call it for a while and a half .

Here we use init Method to do a demonstration .

init Method is a method of initializing an application or module , But here module The parameter does have a null value .

init Initialize application First make a breakpoint to see the relevant data information .

The printed result is empty , This is a mistake some new learning partners will make , Because this method cannot be called only once .

If the initialization module is empty, then there is no need for this method to exist .

 Breakpoint view module Value  Breakpoint print results This should be the right way to do it .

 The right breakpoint way  Print the results There will be a problem , This init The method is obviously called twice , So where is the next call !

If you don't know the new technique , A series of breakpoints will be printed , See where it's executed , Like here init To print on top of .

That is to say initialize In that method, print and make breakpoints , But it's troublesome , And it's possible to waste a lot of time and still not find the right place .

The trick is debug_backtrace()

This method produces a backtracking , All call locations of a method are displayed .

How to use it is shown in the following figure , Only need to debug_backtrace This method can be printed out .

 Usage method  Print the results 1  Print the results 2

Based on the data obtained , It can be very fast positioning .

The first time was in app Class 215 That's ok .

 First call init The place of
First call init The place of

The second time was in thinkphp/library/think/route/dispatch/Module.php Class 60 That's ok

 The second call place
The second call place

You can make a print here , Take a look at this module Is it index

 The breakpoint  Print the results So with this method, you can locate the call location very quickly .

3、 ... and 、 Initialization application of framework execution process init analysis

Here's a tip for you debug_backtrace The actual combat demonstrates how to see where a method is executed .

And the case is also used init This method is used to demonstrate , Because the next step is to deal with init This is a way to get a deeper understanding of .

stay init The main thing to do in the method is described clearly in the above brain map .

  • Positioning the module from the beginning , That's right in the second verse init Method call , The corresponding module will be passed in
  • load app In the catalog tags file , stay tags Inside the file is the file that defines the behavior extension . The hook execution defined in the previous facade article is set in this file .
  • load common file , Public documents , So public files are loaded here .
  • Load helper function file helper, In the helper function, there is a method that we are particularly familiar with , That's it dump. That's why it's used in some places dump Reasons for reporting errors .
  • Load middleware file , The direct here is direct loading app The middleware file under Directory , But in the framework we need to define a directory as http, Define middleware files in this directory .
  • Register the container object instance of the service , The registration here uses the container class bindTo Method for binding registration .
  • Read configuration file , This paragraph has been explained in detail in the section of loading configuration file , I won't mention it here . The configuration file will be read in two places. One is under the first step module config file , The other is config The configuration file under the directory .
  • Set module path , The module obtained in the first step will be carried out env In the environment variable configuration
  • The last step is to update the configuration of the object instance in the container , What has been updated in the following article will be detailed to you .
    /**
     *  Initialize an application or module
     * @access public
     * @param  string $module  Module name
     * @return void
     */

    public function init($module = '')
    
{
        //  Locate the module directory
        $module = $module ? $module . DIRECTORY_SEPARATOR : '';
        /**
         *  for the first time :D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\
         *  The second time :D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\
         */

        $path   = $this->appPath . $module;

        //  Load initialization file
        if (is_file($path . 'init.php')) {
            include $path . 'init.php';
        } elseif (is_file($this->runtimePath . $module . 'init.php')) {
            include $this->runtimePath . $module . 'init.php';
        } else {
            //  Load behavior extension file
            if (is_file($path . 'tags.php')) {
                $tags = include $path . 'tags.php';
                if (is_array($tags)) {
                    $this->hook->import($tags);
                }
            }

            //  Load public file
            if (is_file($path . 'common.php')) {
                include_once $path . 'common.php';
            }

            if ('' == $module) {
                //  Loading system helper functions
                include $this->thinkPath . 'helper.php';
            }

            //  Loading middleware
            if (is_file($path . 'middleware.php')) {
                $middleware = include $path . 'middleware.php';
                if (is_array($middleware)) {
                    $this->middleware->import($middleware);
                }
            }

            //  Register the container object instance of the service
            if (is_file($path . 'provider.php')) {
                $provider = include $path . 'provider.php';
                if (is_array($provider)) {
                    $this->bindTo($provider);
                }
            }

            /**
             * $path : "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\"
             *          "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\"
             */

            //  Auto read configuration file
            if (is_dir($path . 'config')) {
                $dir = $path . 'config' . DIRECTORY_SEPARATOR;
            } elseif (is_dir($this->configPath . $module)) {
                // D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\config\
                $dir = $this->configPath . $module;
            }
            // scandir: Read the files in the directory in ascending order
            //  Return is config All files in directory
            $files = isset($dir) ? scandir($dir) : [];

            foreach ($files as $file) {
                /**
                 * $this->configExt: The suffix of the configuration file
                 * pathinfo The file suffix is returned , About pathinfo There are three optional parameters PATHINFO_DIRNAME、PATHINFO_BASENAME、PATHINFO_EXTENSION, Return only the file name , File directory name , File extension
                 */

                if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {
                    /**
                     *  The two parameters are
                     * 1. Catalog +config A file in a directory
                     * 2.config Directory file name
                     */

                    $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));
                }
            }
        }

        $this->setModulePath($path);

        if ($module) {
            //  Update the configuration of the object instance in the container
            $this->containerConfigUpdate($module);
        }
    }

Here comes a code , You can look at the code above the execution process , Each step is explained briefly .

Kaka personal opinion to optimize the source code

The code click in setting up the module is not very strict , because init Methods are executed in two places .

The first module is empty , This code execution is meaningless .

Next, we make a judgment when updating the configuration of the object instance of the container , Judge whether this parameter of the module is empty , If it is not empty, it will be executed .

So the same thing , I feel that setting the module path should also be in this judgment .

Although the second execution will cover the first result , But it's better to use it in this way .

 Suggestions for source code modification
Suggestions for source code modification

Four 、 Update the object instance in the container

In the last section, this is the last thing , Then update the configuration of the instance , What's new , How to update is not explained .

It will be explained in this section , You can also look at it with the mind map of the preface .

  • First of all config All configuration information under the directory is obtained
  • from app The exception handling class will be registered in the 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 pack after determining the module , Language pack function can realize multi language function , I've written an article about multilingualism before , If you are interested, you can check it out .
  • The last step is based on app The three attributes in the configuration file are used for cache processing

In this section, the most important feeling is the content in the figure below .

 Update the object instance in the container We can trace one or two methods at will to see what's going on there .

Tracking methods Db::init()

When the tracking method comes over, you can see that it's right Db Class config Property to assign , hold database Assign the value in to Db Class config attribute .

 track Db::init Method Tracking methods $this->middleware->setConfig()

Come to the middleware class , You can see that the configuration of this class is merged with the parameter class passed in , It's also going on config Assignment of a property .

Follow the example above Db Class init The effect of method implementation is consistent .

It's in the middle of Update the object instance in the container In this picture, you can see that the purple part is not referenced in this class .

So how can this be implemented ! Because App Class inherits the container class , There are four magic methods in the container class , One of them __get Method , That method is executed when getting properties that do not exist .

In the magic method __get A method is executed make Method , This make The method has been said many times , This method will eventually return an instance of the application , 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 ability and thinking .

 Setting and configuration of middleware
Setting and configuration of middleware

5、 ... and 、 On debugging mode and code redundancy

This section gives a brief description of debugging mode , And the redundancy of framework code will be simply proposed .

No one writes code that has no holes , If there is, then you have not reached certain attainments .

Debug mode

In the first section, we only mention initialize The first half of the method , Because all the talk before this section is about application initialization init The content of .

Next, you will give a brief explanation of the content of this piece .

  • from app From the configuration file app_debug Configuration item for
  • Set the environment variable debug Level
  • When... In the frame debug It will be executed when it is closed ini_set This method , This method is to assign a value to a configuration option .

The following content is not easy to understand , They are usually not used at work .

  • ob_get_level: Returns the nesting level of the output buffer mechanism , So how to understand ! In fact, when the cache does not work, it will return 0.
  • ob_get_clean: This function will return the contents of the output buffer and terminate the output buffer . If the buffer has no valid content, it returns false. In essence, it is equivalent to executing at the same time ob_getcontens() and ob_end_clean().
  • ob_start: Turn on the output control buffer

Let's get to know these three for a while , Later, if you have the opportunity, you will have an article to explain .

 Debug mode About framework code redundancy

This is just a personal view of Kaka .

You can take a look at this part of the code first , These two codes are not very familiar , That's right. That's right init Method in the container object instance configuration update, see .

 Redundant code Pictured

 Redundant code comparison This is the personal opinion of Kaka , Because the click is aimed at 5.1 Do the source code interpretation , I don't know if there are any changes in the new edition .

6、 ... and 、 summary

This section mainly discusses the initialization application in the framework execution process .

As for the app Class run There are also a lot of execution procedures under the method, which are not explained too much in this section .

In the process of reading the source code, I gave you a very good little skill , That's how to see where a method is executed .

This method is debug_backtrace, You need to use this method several times to know how to use it , Because there is a lot of useless information in the printed results .

This method is very effective in debugging the source code , Make good use of this method .

In is the initialization application init The method is introduced in detail .

Among them, the best design is to update and configure the object instance in the container , Read all the configuration first , Then, the configuration settings are made through the methods of each class .

This code planning and design idea is worth learning .

Finally, we talk about the code redundancy of debugging mode and framework , About debugging mode, here we give you a wake-up project, online debugging mode must be turned off .

Otherwise, your project is similar to the existence of streaking , There's no safety at all .

What's a little hard to understand is the buffer , About this content, Kaka thinks that there is no need to go to the top for the time being , First of all, we should know and understand, and then we should carry out in-depth research .

This content of buffer is estimated to have worked for three or four years, and few people use it , So get to know it first , Know what's going on , After studying in the later stage of Kaka, I will give you a supplement .

Until here, the initialization application of the framework's execution process is finished , There is nothing to learn in this section , It is mainly the code design pattern and implementation ideas .

Finally, we must follow the source code to see the picture !

 Insert picture description here
Insert picture description here

Keep learning 、 Keep blogging 、 To insist on sharing is the belief that khaka has been holding since he was employed . I hope the articles in the Internet can bring you a little help . I'm Kaka , See you next time .

版权声明
本文为[Click-]所创,转载请带上原文链接,感谢