ThinkPHP framework bootstrap analysis _ PHP Tutorial

Source: Internet
Author: User
ThinkPHP framework bootstrap analysis. This type of file is in: ThinkPHPLibraryThinkThink. class. the php class can be said to be the core class Library of the ThinkPHP framework. it is responsible for loading many configurations and registering the core system extensions (automatically loading class files in: ThinkPHP/Library/Think. class. php

This class can be said to be the core class library of the ThinkPHP framework. it is responsible for loading many configurations and registering core system extensions (automatically loading class libraries, exception handling, error handling, etc ), management and Maintenance of class instances and alias ING can be said to be a framework factory (this class has some disadvantages of object-oriented, such as: it violates the single responsibility of object-oriented, and its responsibility function is complex, there are a lot of associated class libraries and files, and there is a worry about getting started ). The functions encountered in the class will be thoroughly analyzed after analysis, and other class libraries involved will be specially explained.

I. class structure

Namespace Think; // defines the namespace class Think {private static $ _ map = array (); // class library alias ing private static $ _ instance = array (); // Save the class instance (this is also unreasonable and will be analyzed when the function is described) static public function start () {} // initialize the static public function addMap ($ class, $ map = '') {} // register the static public function getMap ($ class ='') of classmap '') {}// obtain classmap public static function autoload ($ class) {}// the class library automatically loads static public function instance ($ class, $ method = '') {}// get Object instance support call class static method static public function appException ($ e) {}// custom exception handling static public function appError ($ errno, $ errstr, $ errfile, $ errline) {}// custom error handling static public function fatalError () {}// static public function halt ($ error) {} // error output static public function trace ($ value = '[think]', $ label = '', $ level = 'debug', $ record = false) {}// add and retrieve page Trace records}

2. Analysis of the start () method initialized by the application. this method contains a set of error and exception handling mechanisms, which are very useful. This method serves as the guiding interface of the ThinkPHP framework to implement error and exception handling, configuration loading, alias ING, behavior registration, including running cache generation, website application directory detection, automatically registers the class library loading behavior.

/*** Initialize the application * @ access public * @ return void */static public function start () {// use the _ autoload () provided in the spl standard library () by default, the function is more efficient and flexible than _ autoload (). // you can use spl_autoload_register (array ('think \ think', 'autoload ')); // We recommend that you use spl_autoload_register (_ NAMESPACE __. '\ Think: autoload'); implement // all the registration methods can use the format above 3 to pass the parameter spl_autoload_register ('think \ Think: autoload '); // register the global script "destructor". functions registered using this method are called before the script ends. In most cases, it is used to handle the fatal error register_s. Hudown_function ('think \ Think: fatalerror'); // sets a custom error handling function for processing the error message set_error_handler ('think \ Think: appError '); // set_exception_handler ('think \ Think: appexception'); // you can set register_shutdown_function (), set_error_handler (), set_error_handler () the three functions are combined to complete custom and diversified error handling modules. // Set the distributed file Storage solution based on the STORAGE_TYPE value. Storage is a factory class, used to manage and maintain distributed file Storage components // The Storage class will be explained in detail later, and the design defect Storage: connect (STORAGE_TYPE) will be pointed out; // according to the running mode in Run the cache directory to generate the compilation cache file APP_MODE .'~ Runtime. php' to reduce IO overhead // The following describes in detail how to generate cache files $ runtimefile = RUNTIME_PATH.APP_MODE .'~ Runtime. php'; // if it is not in debugging mode and the compilation cache file exists, directly load the compilation cache if (! APP_DEBUG & Storage: has ($ runtimefile) {Storage: load ($ runtimefile);} else {// Determine whether the compiled cache file exists, if it exists, delete if (Storage: has ($ runtimefile) Storage: unlink ($ runtimefile); // pre-compiled content variable $ content = ''; // Determine whether the running mode configuration file exists. if not, load MODE_PATH.APP_MODE. '. php '. The Running mode configuration file will affect loading different class libraries and configurations as follows. // The running configuration file will be explained in detail later. $ mode = include is_file (CONF_PATH. 'core. php ')? CONF_PATH. 'core. php ': MODE_PATH.APP_MODE. '. php '; // All the following configuration items are loaded to overwrite the previous configuration items according to the loaded order. Generally, the default configuration of ThinkPHP is loaded first, reload the application configuration // The core subscript determines the core class to be loaded and the function file foreach ($ mode ['core'] as $ file) {if (is_file ($ file )) {include $ file; // if not in debugging mode, compile the file content and store it in the pre-compiled content variable if (! APP_DEBUG) $ content. = compile ($ file) ;}// config subscript determines the core configuration file to be loaded foreach ($ mode ['config'] as $ key => $ file) {// Determine whether the subscript is a number. if not, the configuration item in the configuration file will be loaded to the corresponding key, which is equivalent to adding a latitude is_numeric ($ key) to the configuration item )? C (include $ file): C ($ key, include $ file);} // if it is not a normal running mode, check whether the application configuration file if ('common '! = APP_MODE & is_file (CONF_PATH. 'config _'. APP_MODE. '. php ') C (include CONF_PATH. 'config _'. APP_MODE. '. php '); // alias subscript record class library alias ing rules, ThinkPHP's original alias mechanism, used to improve the efficiency of automatic loading if (isset ($ mode ['Alias']) {// from this code, we can see that the alias rule can be an array, or use the rule array as a file self: addMap (is_array ($ mode ['Alias'])? $ Mode ['Alias']: include $ mode ['Alias']);} // load the alias configuration defined in the application if (is_file (CONF_PATH. 'Alias. php ') self: addMap (include CONF_PATH. 'Alias. php '); // The tags subscript is used to identify system behavior. the behavior extension is implemented by the Hook class if (isset ($ mode ['tags']). {// from this code, we can see that the tags rule can be an array, or use the rule array as a file Hook: import (is_array ($ mode ['tags'])? $ Mode ['tags']: include $ mode ['tags']);} // load the behavior extension configuration in the application if (is_file (CONF_PATH. 'tags. php ') // allows the application to add the development mode configuration definition Hook: import (include CONF_PATH. 'tags. php '); // load the underlying language pack of the framework. the DEFAULT_LANG configuration item in the core configuration file determines L (include THINK_PATH. 'Lang /'. strtolower (C ('default _ LANG ')). '. php '); // if not in debug mode, the compiled cache file if (! APP_DEBUG) {// namespace {} is used to declare that the namespace in the code block belongs to the global namespace. // This code is used to generate the php code for loading the alias ing $ content. = "\ nnamespace {Think \ Think: addMap (". var_export (self: $ _ map, true ). ");"; // L (". var_export (L (), true ). "); generate a language to load code // C (". var_export (C (), true ). '); generate the configuration item to load the code // Think \ Hook: import ('. var_export (Hook: get (), true ). '); generate the hook to load the code $ content. = "\ nL (". var_export (L (), true ). "); \ nC (". var_export (C (), true ). '); Think \ Hook: import ('. var_export (Hook: get (), true ). ');}'; // remove comments and line breaks from the $ content variable and write them to the cache file Storage: put ($ runtimefile, strip_whitespace ('
 

3. implement addMap () and getMap () method analysis by using the class library alias ing mechanism. this mechanism uses Think: _ map variable to store alias ing records and uses Think: addMap () add or modify the alias ing record and use Think: getMap () to obtain the alias ing record.

/*** Register or modify the ing record of the class library alias * @ access public * @ param class String | if the Array key is the class library alias, the key value is the actual position of the class library; if the String represents the class library alias * @ param map String if the class is a String, this parameter represents the actual position of the class library, otherwise it does not make sense * @ return void */static public function addMap ($ class, $ map = '') {// checks whether the class is an array. if yes, merges the Alias Records of the current class library. if the same record exists, it overwrites if (is_array ($ class )) {self: $ _ map = array_merge (self: $ _ map, $ class);} else {// if the class is not an array, store it as an alias in the class library alias record, and use map as the actual class library location self: $ _ map [$ class] = $ map ;}} /*** obtain the actual address of the class library based on the alias * @ param class String class library alias * @ return Array | String | NULL if the class is empty, all class library Alias Records are obtained, otherwise, return the class library location corresponding to the alias */static public function getMap ($ class = '') {// if the class is empty, directly return all class library Alias Records if (''= $ class) {return self: $ _ map; // Determine whether the corresponding alias is in the alias ing record, if the actual address of the returned class library exists, no returns null} elseif (isset (self: $ _ map [$ class]) {return self :: $ _ map [$ class] ;}else {return null ;}}

IV. Analysis of the autoload () method of the automatic loading mechanism of the ThinkPHP class library. this method is registered by the first code in the Think: start () method to implement spl_autoload_register ('think \ Think :: autoload ');

/*** Automatically load the class library * @ param string $ class object class name * @ return void */public static function autoload ($ class) {// determine whether there is an alias ing // Mark a bug. if Think: addMap ('think \ test') is used, the alias registration is complete, and the program logic is not rigorous, there will be no major security issues. you can ignore this. // For details, refer to the Think: addMap () method implementation if (isset (self: $ _ map [$ class]). {include self: $ _ map [$ class]; // We recommend that you specify urn here; // Determine whether the \ symbol exists, if yes, use the namespace loading mechanism. // The configuration does not conform to 'app _ AUTOLOAD_PATH '=> '', // the automatically loaded path is valid after the APP_USE_NAMESPACE is disabled. // check whether Use naming rules in the class name instead of using APP_USE_NAMESPACE configuration. of course, this configuration mainly applies to the routing module and will be explained later} elseif (strpos ($ class ,'\\')) {// Obtain the namespace's first name range $ name = strstr ($ class, '\', true ); // Determine whether the first namespace name range is in the Think agreed range class, and the directory if (in_array ($ name, array ('think ', 'org ', 'behavior', 'com', 'Vendor') | is_dir (LIB_PATH. $ name) {// The namespace under the Library Directory is automatically located $ path = LIB_PATH ;} else {// Check the custom namespace. Otherwise, use the module as the NAMESPACE $ namespace = C ('autoload _ NAMESPACE '); $ path = Isset ($ namespace [$ name])? Dirname ($ namespace [$ name]). '/': APP_PATH;} // The naming rules of the ThinkPHP namespace are based on the directory principle of LIB_PATH and APP_PATH as the root directory, you can also customize the root directory of the naming rule for the AUTOLOAD_NAMESPACE configuration item $ filename = $ path. str_replace ('\', '/', $ class ). EXT; // determine whether a file exists. why not judge whether the file exists when registering an alias? Can I ignore some problematic alias ING and use the correct loading rules? If (is_file ($ filename) {// if you are running in a windows environment, use strpos to check whether the case sensitivity is consistent, if they are inconsistent, the system returns if (IS_WIN & false === strpos (str_replace ('/', '\', realpath ($ filename), $ class. EXT) {return;} // Import class file include $ filename; // Here we recommend return ;}} else {// You do not need to determine whether to configure the APP_AUTOLOAD_LAYER according to the APP_USE_NAMESPACE value in the configuration file. // as long as the namespace is not used in the class library loading, the following rules will be called to find the class library (to be instantiated) class cannot declare naming rules) foreach (explode (',', C ('app _ AUTOLOAD_LAYER ') as $ layer) {// judge the last few class names If (substr ($ class,-strlen ($ layer) =layer layer) {// load the corresponding class file under the current module, in fact, you can directly determine whether the file exists and use include to load the file. there is no need to call the require_cache function. // The above is my personal opinion, because the above loading mechanism is not used, I think it should be uniform and automatic loading of class files does not require a limit on loading once. if it has already been loaded, this method will not be called. If (require_cache (MODULE_PATH. $ layer. '/'. $ class. EXT) {// return the return directly when the file is successfully loaded} // automatically searches for and loads the file foreach (explode (',', C ('app _ AUTOLOAD_PATH ') as $ path) {// the same as above. can I load the file by calling the import () method or unifying it? If (import ($ path. '.'. $ class) // if the class is successfully loaded, return ;}}}

5. management instance or 'cache' static method call result instance () method analysis. previously in the class structure analysis, it was said that the $ _ instance variable is not reasonable to save the class instance, this class can also call static methods of the class and 'cache' the result. I put forward some personal opinions in this method comment, not to say that the design of this method is unreasonable. this is the ThinkPHP proprietary method after all, the design of any project does not consider many problems of a method as I do. The first problem is that it is sufficient to meet the project application requirements. If you see this article, you can think about whether there are many classes in the project and there is no need for multiple instances (without restrictions ), if so, you can design a pseudo Singleton factory suitable for your project to manage these instances.

/*** Obtain the object instance to support calling the static method of the class * resolution: I regard this class as a pseudo Singleton factory. it is not strictly required that the class is not a singleton, this method can be used to obtain class objects in a unified manner and realize the Singleton mode (extremely suitable for a flexible language like php). * This is a singleton mode and the factory is unqualified, because the management class is not strictly required to comply with the singleton mode constraints. * Problem: this method indicates that this class can call static methods of the class, and does not stipulate that static methods must return instances of the class (self) and can return any results, this surprised me. * If I want to cache the results of class method calls, should I provide the parameter options for passing methods? * If you only want to control the instances of the class (for example, to manage the classes strictly in the Singleton mode, you must use the static method), should you describe or check the return value in the method? * Confused: after all, this is not a method provided to the application (of course, it can be used, and the original design is definitely not. this is a convention set by the ThinkPHP development team (verbal constraints on the use of methods ?) * This at least gives us an inspiration. we can manage the pseudo Singleton mode like this (verbal constraints are more reliable than verbal constraints ), I have previously designed such a factory class in a project (at that time, I have not analyzed the source code of any product) * @ param string $ class object class name * @ param string $ static method name of the method class * @ return object */static public function instance ($ class, $ method = '') {// Generate an instance management identifier $ identify = $ class. $ method; // determine whether a change class instance id if (! Isset (self: $ _ instance [$ identify]) {// determines whether the class exists. in this case, the automatic loading mechanism cannot be used, you must load the class file if (class_exists ($ class) {// instantiate the class before calling this method, we can see that we cannot strictly manage the singleton class $ o = new $ class (); // determine whether to call static methods, and determine whether the class has this method if (! Empty ($ method) & method_exists ($ o, $ method) // return the call result (unknown) self :: $ _ instance [$ identify] = call_user_func (array (& $ o, $ method); else // storage class instance object self :: $ _ instance [$ identify] = $ o;} else // output error message self: halt (L ('_ CLASS_NOT_EXIST _'). ':'. $ class);} // return the instance object return self: $ _ instance [$ identify];}

6. Analysis of built-in error handling and exception handling in ThinkPHP. The appException () method is implemented by the set_exception_handler ('think \ Think: appexception') statement in Think: start. The appError () method is implemented by the set_error_handler ('think \ Think: appError ') in Think: start (); statement, and the fatalError () method is implemented by the Think: start () register_shutdown_function ('think \ Think: fatalerror'); statement implementation. The halt () method is used to output important error messages and exceptions and terminate program execution. The trace () method is used to record and manage error messages in the Trace debugging tool.

/*** Custom exception handling ** @ access public * @ param mixed $ e exception object * @ param void */static public function appException ($ e) {$ error = array (); // get exception error information $ error ['message'] = $ e-> getMessage (); // get backtrace () trace information $ trace = $ e-> getTrace (); // determines whether the exception is thrown by the exception handling method, thinkPHP custom throw exception handling function if ('E' = $ trace [0] ['function']) {$ error ['file'] = $ trace [0] ['file']; // get the error file $ error ['line'] = $ trace [0] ['line']; // get the error line number} else {$ error ['file '] = $ E-> getFile (); // get the error file $ error ['line'] = $ e-> getLine (); // Get error row number} // formatted error backtracking information $ error ['Trace '] = $ e-> getTraceAsString (); // write to error Log :: record ($ error ['message'], Log: ERR); // send the 404 message header ('http/1.1 404 Not Found '); header ('status: 404 Not Found '); // displays the error message self: halt ($ error );} /*** custom error handling ** @ access public * @ param int $ errno error type * @ param string $ errstr error message * @ param string $ errfile error file * @ Param int $ errline error line * @ return void */static public function appError ($ errno, $ errstr, $ errfile, $ errline) {switch ($ errno) {// Some important error messages will affect the subsequent program execution case E_ERROR: case E_PARSE: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: // clear the output buffer (I don't know where to enable it, but will be encountered in later analysis) ob_end_clean (); // In fact, it is to clear the default output error information of php // error message $ errorStr = "$ errstr ". $ errfile. "Row $ errline. "; // determines whether to write error logs based on whether the LOG_RECORD records error information. If (C ('log _ RECORD ') LOG: write ("[$ errno]". $ errorStr, Log: ERR); // output error message self: halt ($ errorStr); break; // error information that can be ignored and will not be output, the error information that can be viewed through SHOW_PAGE_TRACE configuration will be recorded in the trace. default: // here the program will continue to be executed. the output buffer cannot be cleared. if you do not want to display such error information, it should be in php. ini adjustment, or use the ini_set () function to change // error message $ errorStr = "[$ errno] $ errstr ". $ errfile. "Row $ errline. "; // record to trace self: trace ($ errorStr,'', 'notic '); break ;}// capture static public function fat with a fatal error AlError () {// The fatal error must be saved to the Log: save (); // Get the previous error message. if there is no error, skip it (⊙ 0 ⊙) if ($ e = error_get_last () {// handle the fatal error message switch ($ e ['type']) {case E_ERROR: case E_PARSE: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: // clear the output cache, causing the program to stop. what else is displayed? ob_end_clean (); // output error message self: halt ($ e ); break ;}}/*** error output * @ param mixed $ error * @ return void */static public function halt ($ error) {$ e = array ();/ /Determine whether it is in debug mode or command line mode if (APP_DEBUG | IS_CLI) {// output error information in debug mode // if the error information is not an array, it traces back the information of the last execution method if (! Is_array ($ error) {$ trace = debug_backtrace (); $ e ['message'] = $ error; $ e ['file'] = $ trace [0] ['file']; $ e ['line'] = $ trace [0] ['line']; ob_start (); // Start to output the cached debug_print_backtrace (); // output a trace information $ e ['Trace '] = ob_get_clean (); // Obtain the output buffer information, and clear} else {$ e = $ error;} if (IS_CLI) {// command line mode, convert to gbk encoding, terminate the program execution and output the error message exit (iconv ('utf-8', 'gbk', $ e ['message']). PHP_EOL. 'File :'. $ e ['file']. '('. $ e ['line']. ')'. PHP_EOL. $ e [' Trace ']) ;}} else {// not in debugging mode, redirected to the error page $ error_page = C ('error _ page '); // Obtain the set error page if (! Empty ($ error_page) {// redirect to the error page redirect ($ error_page);} else {// determines whether to display detailed error information based on the SHOW_ERROR_MSG configuration, or is the error message set with ERROR_MESSAGE $ message = is_array ($ error )? $ Error ['message']: $ error; $ e ['message'] = C ('show _ ERROR_MSG ')? $ Message: C ('error _ message') ;}// call the error message display template according to the TMPL_EXCEPTION_FILE configuration, otherwise, the default ThinkPHP template $ predictionfile = C ('tmpl _ prediction_file ', null, THINK_PATH. 'tpl/think_exception.tpl '); include $ exceptionFile; exit; // It is very important to terminate the program. }/*** ADD and retrieve page Trace records * @ param string $ value variable * @ param string $ label * @ param string $ level log level (or the page Trace tab) * @ param boolean $ record whether to record logs * @ return void */static public function trace ($ value = '[think]', $ label = '', $ level = 'debug', $ record = false) {// use static variables to store Trace records static $ _ trace = array (); if ('[think]' ===$ value) {// Get trace information return $ _ trace;} else {// error message $ info = ($ label? $ Label. ':':''). print_r ($ value, true); $ level = strtoupper ($ level); // converts the error level to uppercase. // if it is an AjAX request or does not display the TRACE debugging tool, or $ record requires logging, so this error message will not be recorded if (defined ('is _ AJAX ') & IS_AJAX) |! C ('show _ PAGE_TRACE ') | $ record) {Log: record ($ info, $ level, $ record ); // write the error information to the log file} else {// Determine whether the error level exists or whether the error type information has reached the error type record limit. configure if (! Isset ($ _ trace [$ level]) | count ($ _ trace [$ level])> C ('trace _ MAX_RECORD ')) {// I am surprised to see why the error type record should be reset when the error type record limit is reached. // instead of not recording the current error message, or delete the first error message and append it to the end. // it is reasonable to ignore the suggestion. Is there a sequence due to debugging errors? solve the previous error first, you will see a new error (whether this is a bit pitfall ⊙ 0 ⊙) $ _ trace [$ level] = array ();} // record error information by Error Type $ _ trace [$ level] [] = $ info ;}}}

VII. Summary: This type of analysis mainly controls php error handling and exception handling knowledge, and understands the basis for defining rules automatically loaded based on namespaces, I am also touched by the IO optimization ideas brought about by the compiling Cache mechanism during ThinkPHP runtime and the optimization brought about by the class library alias mechanism and automatic class loading. When analyzing this class, I raised several questions about this class outside the ThinkPHP application. this is only for my understanding and cognition of object-oriented design and is not a detailed reference.















The plugin class can be said to be the core class library of the ThinkPHP framework. it is responsible for loading many configurations and registering core system extensions (automatic loading class...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.