File loading --- understanding the first step of a project, --- project. File loading --- understanding the first step of a project --- when I first wrote php, I always worried about this problem: can I load a new class to a corresponding class file here? File loading --- understanding the first step of a project, --- project
When I first wrote php, I always worried about this problem: Can I load a new class to a corresponding class file? After all, a Fatal Error is reported as soon as the operating system runs. The ** file cannot be found, and the class cannot be instantiated. this is a very "low-level" Error, for fear of jokes from others. So every time I take a new task, I always want to figure out the loading process (I used to know only a few html tags and styles, but I don't know if it is web development ), sometimes I read it and said that I still have the leisure time to read it. I can write the logic quickly. just do this ...... you know, of course, you are sure you are. D: I found that the original process is similar.
During development in an IDE, for example, C ++/Java, a new project is generally created, and a new file is added to the specified directory through the IDE, and then # include/Import comes in, php makes this step more procedural. The File loading process basically determines the directory structure and file classification of the project (framework or self-built project.
No matter whether the framework or a self-built project has to have an entry file, some basic information, such as the configuration file and general method, should be loaded in advance. The basic method is to manually load a single file, use one of the following four methods:
Include, require, include_once, require_once
include('config.php'); require('database.php');
When loading class files, a small part of them are directly loaded. for example, common methods are written as static methods in a class Utilities, because there are a lot of methods to be used later (such as error output, curl request, random string generation ...), therefore, it is encapsulated with classes and is usually loaded together when the configuration file is loaded.
Include ('utilities. php ');
The more common case is the dynamic loading of classes. First, let's talk about the loading method to see when a class and instance will be used:
1. the most obvious, $ obj = new A; its variants $ className = 'a'; $ obj = $ className; are the same;
2. call static methods, static variables, and constants of the class, that is, Utilities: httpRequest (), Utilities: $ instance, Utilities: HOST;
3. the callback function is used in php functions, the most typical call_user_func_array () (call_user_func), and other places where callback is used, such as array_walk and array_map in the array, they need a callback function as a parameter.
Callback functions are flexible, not only simple functions, but also object methods, including static class methods. Because the object method or static method can be used, the corresponding class file should also be loaded during this time. Since php5.3, callback functions can also be implemented in JavaScript using anonymous functions.
Class A {public static function cube ($ var) {return pow ($ var, 3);} public function twice ($ var) {return 2 * $ var ;}} // use the static method of the class $ num = call_user_func ('A: cube ', 5); // use the object $ obj = new; $ num = call_user_func_array (array ($ obj, 'TWICE '), array (7 ));
Strictly speaking, the call_user_func_array in the above example has already instantiated the object before, but it can also use static methods like this.
The first thing to understand is why dynamic loading is required. Php is a scripting language. when we access php, scripts are used as available resources. for example, the root directory now has an index. php file, it does not include any other files, when we directly use localhost/index. you can access index when using php. all resources in php, if index. php defines A common class A. when this script instantiates an object named A, the program will respond like this: Oh, I have seen the definition of, you can instantiate it directly (without loading other files ). If there are many classes such as class B, C, and D, they are all written in index. obviously not in php, write it in other files and include it in again (include is already working on loading). This is also "visible" for the program.
However, with the increase of system functions, more and more classes have different functions. some directly define database operations, read database data, and others control the methods to run when accessing scripts, some are the pages to be displayed, some are the third-party core libraries we reference, so when we put all the files in a directory, although we can directly include the load, however, the placement of these files is messy and difficult to find, and the maintenance cost is high. Well, create several directories under the root directory. Directory A stores scripts for dealing with databases, and directory B is the configuration information file of the system, directory C is the script that controls the entry control method when we enter the program. Directory D is the page that will be displayed on the browser ......
As a result, the MVC architecture gradually evolved. we can no longer directly include the code as before. the script is stored in a specific directory. for example, the Controller Directory stores various controllers. when the Controller is loaded, we need to include ('root/Controller/indexController. php '), every time you get a string of include in front of the file, not only does it look a headache, it makes people feel tired. Since there is a ready-made method to get the current file path and class name, why not map the class name to the file name, as long as the scripts of the Controller class are all placed under the Controller subdirectory of the ROOT directory, you can write a method. as long as the scripts are Controller classes, run include (ROOT. 'controller /'. $ className. '. php '); ROOT is the ROOT directory constant, $ className is the input class name, as long as it is a model class, so include (ROOT. 'model /'. $ className. '. php '); the function is used to dynamically control the directory to which the query is located. this project may be like this:
Virtually, a rule is established for the corresponding class name and file name, and the corresponding rules for the file and the directory where it is located. Which of the following directories and files under the project are available? Ah, it turned out to be the Controller of the Controller, the Config of the configuration information, and so on. once again, the structure of the project is invisible. as mentioned above, the function is used according to certain conditions (input parameters) we can see the directory to which the file will be loaded automatically, instead of the dead include. this is the so-called dynamic loading of files.
Therefore, when you want to create a ** class file, you will know that in this project, I should put it in this directory, and the file name should be the same as the class name, in this way, it will surely be loaded ~~~ The next step is a pleasant process for writing business logic ".
After knowing when it will be dynamically loaded and why it will be dynamically loaded, the next step is to implement it, that is, using the function mentioned above to load a file, it is necessary to write this "function" to implement this process. There are three common methods:
1. _ autoload
This is what I used when I first learned it. magic functions, as long as a php program is defined, will automatically call a class to automatically load files dynamically, since it is a function, we need to make the program's definition of _ autoload visible. where else will it be called? In general, as the method used in most of the subsequent programs, we will put it in a separate file and load it in at the entrance of the program. several files in a project must be manually included, you can include the configuration information separately at the beginning or in the configuration information. Its prototype:
Void _ autoload (string $ class)
The name of the class currently loaded by the parameter (note that if there is a namespace, it contains the namespace prefix). The following is a simple example of the above image structure:
// File: autoload. php // ROOT is the defined ROOT directory constant function _ autoload ($ className) {try {if (file_exists (ROOT. 'controller /'. $ className. '. php ') {// Check Controller include (ROOT. 'controller /'. $ className. '. php ');} else if (file_exists (ROOT. 'model /'. $ className. '. php ') {// Check Model include (ROOT. 'model /'. $ className. '. php ');} else if (file_exists (ROOT. 'Lib /'. $ className. '. php ') {// Check Lib include (ROOT. 'Lib /'. $ className. '. php ');} else {// The file throw new Exception ("ERROR: can't find file {$ className }. php ") ;}} catch (Exception $ e) {echo $ e. getMessage (); exit ;}}
2. spl_autoload_register
_ Autoload is actually similar, but it is defined in php. if something is written and called now, tell the program, I don't need _ autoload to load files. I have defined a method for loading files (for example, the name is loadClass). when I need to load a class file in the future, you can use it. Spl_autoload_register is such a method that can tell the program to do this, and the custom loading method will be more flexible, you can specify multiple loading functions, the spl_autoload_register function puts these functions in a queue and activates them one by one during the call: "If there must be multiple autoload functions, spl_autoload_register () allows for this. it uses tively creates a queue of autoload functions, and runs through each of them in the order they are defined. ", on php.net (http://php.net/manual/en/function.spl-autoload-register.php) it does, s Pl_autoload_unregister logs out of the load function queue.
In addition, the spl_autoload_functions () function can obtain the functions we have registered. the spl_autoload_call ($ class) function tries to call all registered loading functions to load class files of $ class.
For the explanation of spl_autoload_register, I understand that if we use spl_autoload_register to register n functions in the loading queue because they are automatically activated, now I want to instantiate a class, failed to load in 1st loading functions, then tried 2nd functions, and the second failed, tried 3rd, ''until the nth function was completed, if the loading is not successful, an error is reported. if the loading is successful in the middle, but it seems a little different.
Or use the directory structure in the previous image,
1. create the indexController. php file under the Controller object, including the class indexController;
2. create the userModel. php file under the "Model" directory, which contains the userModel class;
3. write a class loading script Autoload. php on the homepage. the code is as follows:
// File: Autoload. php define ('Ds', DIRECTORY_SEPARATOR); define ('root', rtrim (dirname (_ FILE __),'/\\'). DS); class Autoload {public static function autoloadRegister ($ loadFunc = 'autoload: loadcontrollerclass', $ enable = true) {return $ enable? Spl_autoload_register ($ loadFunc): spl_autoload_unregister ($ loadFunc);} // load the controller class public static function loadControllerClass ($ className) {if (file_exists (ROOT. 'controller '. DS. $ className. '. php ') {// Check Controller include (ROOT. 'controller '. DS. $ className. '. php '); echo ROOT. 'controller '. DS. $ className. '. php '.'
';} Else {echo "ERROR: can't find file {$ className }. php in ". ROOT. "Controller"; exit ;}}// load model class public static function loadModelClass ($ className) {if (file_exists (ROOT. 'model '. DS. $ className. '. php ') {// Check Model include (ROOT. 'model '. DS. $ className. '. php '); echo ROOT. 'model '. DS. $ className. '. php '.'
';} Else {echo "ERROR: can't find file {$ className}. php in". ROOT. "Model"; exit ;}}}
4. test the script to test whether the class can be loaded.
// Register two loading functions: Autoload: autoloadRegister ('autoload: loadcontrollerclass'); Autoload: autoloadRegister ('autoload: loadmodelclass '); // view the total registered load functions echo 'register functions =>'; Print_r (spl_autoload_functions (); // instantiate a Controller class and a Model class $ indexCon = new indexController; $ userMod = new userModel;
The result is:
This is not scientific. the spl_autoload_functions array shows that both functions have been registered. However, when the userModel class is instantiated, it is still found in the Controller Directory. the automatic loading method called by instantiation of the two classes is Autoload :: loadControllerClass, so an error is reported when loading the userModel class file ...... note that the third parameter of the spl_autoload_register method is to add a function to be loaded in the stack, so I wrote another similar class otherLoad, just to put the loadModelClass method into the queue header:
Class otherLoad {public static function autoloadRegister ($ loadFunc = 'otherload: loadmodelclass', $ enable = true) {// by default, the loadModelClass is placed at the head of the team. return $ enable? Spl_autoload_register ($ loadFunc, true, true): spl_autoload_unregister ($ loadFunc);} // load model class public static function loadModelClass ($ className) {if (file_exists (ROOT. 'model '. DS. $ className. '. php ') {// Check Model include (ROOT. 'model '. DS. $ className. '. php '); echo ROOT. 'model '. DS. $ className. '. php '.'
';} Else {echo "ERROR: can't find file {$ className}. php in". ROOT. "Model"; exit ;}}}
Test is like this
// Register three loading functions: Autoload: autoloadRegister ('autoload: loadcontrollerclass'); Autoload: autoloadRegister ('autoload: loadmodelclass'); otherLoad :: autoloadRegister ('otherload: loadmodelclass'); // You can check which load functions echo 'register functions =>'; Print_r (spl_autoload_functions (); // instantiate a Controller class and a Model class $ indexCon = new indexController; $ userMod = new userModel;
The result is as follows:
We can see that this time it was not successful when loading the indexController class, because it only called the loadModelClass method and then looked at the array returned by spl_autoload_functions. the loadModelClass method of the otherLoad class is at the beginning. it is hard to say that, the function is used for automatic loading only before the function queue is loaded. other functions are invalid? What is the situation?
If you use spl_autoload_call ('indexcontroller') to "call all registered functions to load the request class", this error is returned.
I 've reviewed other people's articles, including blogs on github, that is, I 've listed the following manual: "You can register multiple loading functions at a time, bala ...... ", has no one tried it, or is there a problem with my understanding> 3 <... (test in win, php version 5.4.10) if this is the case, the spl_autoload_register method does not make much sense. why ......
Spl_autoload_register has the following interesting points:
1. a function can only be loaded to the function queue once. this is also true for repeated loading;
2. if spl_autoload_register does not specify the function to be loaded (the first parameter), the loading function spl_autoload is used by default (functions are similar to _ autoload, which is the default implementation form)
3. if spl_autoload_register specifies _ autoload as the loading function, you must implement _ autoload;
4. spl_autoload_register and _ autoload are implemented at the same time, and the loading function registered by spl_autoload_register is preferentially used.
In the above cases, you can find test examples from the notes in php.net. it is interesting to write for reference by foreigners. Pay attention to the above 2nd points. for example, if you create a directory in the root directory, use the default function to load:
// Set the file name extension to load only *. php file spl_autoload_extensions ('. php '); // by default, spl_autoload is used to load files. only files in the current directory can be loaded: lowercase class name. php spl_autoload_register (); // Test // $ obj = new;
Spl_autoload_extensions: specifies only the extension types of files to be loaded. the default value is the. php or. inc file. set it to. php and call the registration function. Create A. php file in the root directory, create A class a, load the file successfully, and change the file name to A. php. This is true for Mac OS X, but Linux is case sensitive. pay attention to this when testing.
It does not need to be automatically loaded, such as CI. it encapsulates the loaded file into a core class CI_Loader. when the program starts, it first includes the necessary scripts (other core classes to be used), and then waits for the necessary use, CI_Loader instance is a property member of the current controller class or model class. it is called to include various models, views, and databases) and helper (helper function.
No matter whether it is used for dynamic loading, it must be ensured that files are placed in different categories and files are named according to certain rules. this is a must for a robust, highly scalable, and easy-to-use project, it is also convenient to write code. Of course, the size of the file to be loaded and the memory size are different. it is also the criteria for judging a framework. Understanding the loading method is not easy to get familiar with a framework structure...
When I first wrote php, I always worried about this problem: Can I load a new class to the corresponding class file...