Home > Article > Backend Development > Detailed explanation of PHP’s automatic loading function
This article is a summary of PHP's automatic loading function, covering PHP's automatic loading function, PHP's namespace, PHP's PSR0 and PSR4 standards, etc.
1. PHP automatic loading function
The origin of PHP automatic loading function
During the PHP development process, if you want to introduce a class from the outside, you usually use the include and require methods to include the file that defines the class. When this is developed on a small scale, there is no big problem. However, in large-scale development projects, using this method will bring about some hidden problems: if a PHP file needs to use many other classes, then a lot of require/include statements will be needed, which may cause omissions or inclusions. Unnecessary class files. If a large number of files require the use of other classes, it will be a nightmare to ensure that each file contains the correct class file, and require_once is expensive.
PHP5 provides a solution to this problem, which is the automatic loading (autoload) mechanism of classes. The autoload mechanism makes it possible for PHP programs to automatically include class files only when classes are used, instead of including all class files at the beginning. This mechanism is also called lazy loading.
To sum up, the automatic loading function brings several advantages:
#No need to use the class before include or require
will only require/include files when using classes, which implements lazy loading and avoids requiring/include redundant files.
#No need to consider the actual disk address of the introduced class, realizing the separation of logical and entity files.
If you want to know more about the automatic loading function, you can check the information:
PHP's class automatic Loading mechanism
Implementation analysis of PHP’s autoload mechanism
Usually when PHP5 uses a class, if it finds that the class is not loaded, it will automatically Run the _autoload() function. This function is customized by us in the program. In this function, we can load the classes we need to use. The following is a simple example:
<span style="font-size: 16px;">function __autoload($classname) { <br> require_once ($classname . "class.php"); <br>}<br></span>
In our simple example, we directly add the class name to the extension ".class.php" to form the class file name, and then use require_once loads it. From this example, we can see that autoload has to do at least three things:
Determine the class file name based on the class name;
Determine the disk path where the class files are located (in our case, in the simplest case, the classes are in the same folder as the PHP program files that call them);
Load classes from disk files into the system.
The third step is the simplest, just use include/require. To realize the functions of the first and second steps, the mapping method between the class name and the disk file must be agreed upon during development. Only in this way can we find its corresponding disk file based on the class name.
When there are a large number of class files to be included, we only need to determine the corresponding rules, and then in the __autoload() function, match the class name with the actual disk file, You can achieve the effect of lazy loading. From here we can also see that the most important thing in the implementation of the _autoload() function is the implementation of the mapping rules between the class name and the actual disk file.
If you need to use many other class libraries in the implementation of a system, these classes Libraries may be written by different developers and have different mapping rules between class names and actual disk files. At this time, if you want to implement automatic loading of class library files, you must implement all mapping rules in the __autoload() function. In this case, the autoload() function may be very complicated or even impossible to implement. In the end, the autoload() function may become very bloated. Even if it can be implemented, it will have a great negative impact on future maintenance and system efficiency.
So where does the problem lie? The problem is that _autoload() is a global function that can only be defined once and is not flexible enough. Therefore, all the logical rules corresponding to class names and file names must be implemented in one function, causing this function to be bloated. So how to solve this problem? The answer is to use an _autoload call stack, write different mapping relationships into different _autoload functions, and then register and manage them uniformly. This is the SPL Autoload introduced in PHP5.
SPL is the abbreviation of Standard PHP Library. It is an extension library introduced in PHP5. Its main functions include the implementation of the autoload mechanism and various Iterator interfaces or classes. SPL Autoload has several specific functions:
##spl_autoload_register: Register __autoload() function
spl_autoload_unregister: Unregister registered functions
- ##spl_autoload_functions: Return all registered functions
- spl_autoload_call: Try all registered functions to load a class
##spl_autoload: Default implementation of __autoload()
- spl_autoload_extensions: Registers and returns the default file extensions used by the spl_autoload function.
The detailed usage of these functions can be found in the detailed explanation of spl_autoload in php
In short, spl_autoload is SPL itself The definition of __autoload() function is very simple. It is to go to the registered directory (set by set_include_path) to find the .php/.inc file with the same name as $classname. Of course, you can also specify specific types of files by registering extensions (spl_autoload_exionsions).
And spl_autoload_register() is the autoload call stack we mentioned above. We can register multiple of our own _autoload() functions to this function. When PHP cannot find the class name When, PHP will call this stack and call the custom _autoload() function one by one to realize the automatic loading function. If we do not enter any parameters into this function, then the spl_autoload() function will be registered.
Okay, this is the bottom layer of PHP automatic loading. The registration mechanism is already very flexible, but what is missing? As we said above, the key to automatic loading is the mapping of class names and files. Different frameworks have different methods for this mapping relationship. It is very flexible, but if it is too flexible, it will appear messy. PHP has a special specification for this mapping relationship, which is PSR PSR0 and PSR4 in the standard.
But before talking about PSR0 and PSR4, we also need to understand the problem of PHP's namespace, because these two standards are not actually aimed at the mapping of class names and directory files, but Is the mapping of namespaces and files. Why is this so? In my understanding, in standard object-oriented PHP thinking, namespaces can be regarded as aliases of class names to a certain extent, so why should namespaces be introduced and what are the advantages of namespaces
2. Namespace namespace
To understand the namespace, first take a look at the introduction of the namespace in the official documentation:
What is a namespace? Broadly speaking, a namespace is a way of encapsulating things. This abstract concept can be found in many places. For example, directories are used in operating systems to group related files, and they act as namespaces for the files in the directory. For example, the file foo.txt can exist in the directories /home/greg and /home/other at the same time, but two foo.txt files cannot exist in the same directory. Additionally, when accessing the foo.txt file outside the directory /home/greg, we must put the directory name and directory separator before the file name to get /home/greg/foo.txt. The application of this principle to the field of programming is the concept of namespace.
In PHP, namespaces are used to solve two types of problems encountered when creating reusable code such as classes or functions when writing class libraries or applications:
1 User-written code and PHP internal classes /Name conflicts between functions/constants or third-party classes/functions/constants
2 Create a (or short) name for a very long identifier name (usually defined to alleviate the first type of problem), improve Source code readability.
PHP namespaces provide a way to group related classes, functions, and constants together.
To put it simply, PHP does not allow two classes, functions or variable names with the same name in the program, so some people are very confused. Then it’s okay if you don’t have the same name? In fact, many large programs rely on many third-party libraries. Name conflicts should not be too common. This is the first problem on the official website. So how to solve this problem? When there is no namespace, the poor programmer can only give the class name a_b_c_d_e_f, where a/b/c/d/e/f usually has its own specific meaning, so that there will generally be no conflicts, but this Long class names are tiring to write and even more uncomfortable to read. Therefore, PHP5 introduced namespaces. The class name is the class name, and the namespace is the namespace. When the program is written/read, the class name is used directly. When running, the machine sees the namespace, which solves the problem.
In addition, namespaces provide a way to group related classes, functions, and constants together. This is also a great use of object-oriented language namespaces. Classes, variables, and functions required for specific purposes are written into a namespace and encapsulated.
After solving the problem of class names, we can finally return to the PSR standard. So how do PSR0 and PSR4 standardize the mapping relationship between files and namespaces? The answer is: restrictions on the naming of the namespace (well, it’s a bit confusing), the location of the class file directory, and the mapping relationship between the two. This is the core of the standard. A more complete description can be found in Modern PHP New Feature Series (1) - Namespace
3. PSR Standard
Before talking about PSR0 and PSR4, let’s introduce the PSR standard. The inventor and standardizer of the PSR standard is: PHP-FIG, and its website is: www.php-fig.org. It was this consortium that invented and created the PSR specification. FIG is the abbreviation of Framework Interoperability Group. It was founded in 2009 by several open source framework developers. Since then, many other members have been selected. Although it is not an "official" organization, it also represents A big part of the community. The purpose of the organization is to unify the coding standards of each project with the lowest level of restrictions to avoid the trouble of each company's own development style hindering the development of programmers. So everyone invented and summarized PSR, PSR is Proposing a Standards Recommendation (Proposing a Standards Recommendation) Abbreviation for Standards Proposal).
For detailed specifications, please view
PSR specification in PHP
The PRS-0 specification is the first set of specifications they issued. It mainly formulates some automatic loading standards (Autoloading Standard). PSR-0 has several mandatory requirements:
1. A fully qualified namespace and class must conform to the structure: "52f0a8d2734c4b535654453e49349ac9(1db0f77747bb2a800b935b09d3ea2286)*f4e9db28b9ff9ba3f3e4b75ebb041388"
2. Each namespace must There is a top-level namespace ("Vendor Name" provider name)
3. Each namespace can have multiple sub-namespaces
4. When loading from the file system, the delimiter (/) of each namespace must be Convert to DIRECTORY_SEPARATOR (operating system path separator)
5. In the class name, each underscore (_) symbol must be converted to DIRECTORY_SEPARATOR (operating system path separator). Within a namespace, the underscore_ symbol has no (special) meaning.
6. When loading from the file system, the qualified namespace and class must end with .php
7. Verdor name, namespaces, and class names can be composed of uppercase and lowercase letters (case sensitive )
The specific rules may be a bit confusing, so let’s start from the beginning.
Let’s first take a look at the general content of the PSR0 standard. Articles 1, 2, 3, and 7 limit the names of namespaces, and Articles 4 and 5 set the mapping relationship between namespaces and file directories. There are restrictions, Article 6 is the file suffix name.
As we said before, how does the PSR standard standardize the mapping relationship between the namespace and the file directory where it is located? It is by restricting the name of the namespace, the location of the file directory and the mapping relationship between the two.
Then we may have to ask, where is the restriction on the location of the directory where the file is located? In fact, the answer is:
ہ
Restrict namespace name + Restrict namespace name and file directory mapping = Restrict file directory
Okay, let’s think about it first Think about it, for a specific program, if it wants to support the PSR0 standard, what adjustments does it need to make?
First, the program must define a mapping function that complies with Articles 4 and 5 of the PSR0 standard, and then register this function in spl_register();
Secondly, when defining a new namespace, the name of the namespace and the directory location of the file must comply with items 1, 2, 3, and 7.
Generally for the convenience of code maintenance, we will only define one namespace in a file.
Okay, we have the name of the namespace that complies with PSR0. Through the mapping relationship that complies with the PSR0 standard, we can get the file directory address that complies with the PSR0 standard. If we store the files correctly according to the PSR0 standard, everything will go smoothly. require the file, we can use the namespace. Isn't it amazing?
Next, let’s take a closer look at what the PSR0 standard specifies?
Let’s take one of the namespaces /Symfony/Core/Request, one of the third-party library Symfony in laravel, as an example to talk about the above PSR0 standard.
##A fully qualified namespace and class must conform to the structure: "52f0a8d2734c4b535654453e49349ac9(1db0f77747bb2a800b935b09d3ea2286)* f4e9db28b9ff9ba3f3e4b75ebb041388”
/Symfony shown above is the Vendor Name, which is the name of the third-party library, and /Core is the Namespace name , generally some attribute information of our namespace (for example, request is the core function of Symfony); finally, Request is the name of our namespace. This standard specification allows people to see the source and function of the namespace very clearly, which is conducive to the development of the code. maintain.
2 . Each namespace must have a top-level namespace ("Vendor Name" provider name)
That is to say, each namespace must have a top-level namespace similar to /Symfony. Why is there such a rule? Because the PSR0 standard is only responsible for the mapping relationship after the top-level namespace, that is, the part of /Symfony/Core/Request, which directory /Symfony should be associated with is defined by the user or the framework itself. The so-called top-level namespace is a namespace with customized mapping relationships, usually the provider name (the name of a third-party library). In other words, the top-level namespace is the basis for automatic loading. Why are the standards set like this? The reason is very simple. If there is a namespace /Symfony/Core/Transport/Request and another namespace is /Symfony/Core/Transport/Request1, if there is no top-level namespace, we have to write two paths and these two Corresponding to the namespace, what if there are Request2 and Request3. With the top-level namespace /Symfony, we only need a directory corresponding to it, and the rest can be parsed using the PSR standard.
3. Each namespace can have multiple sub-namespaces
This is very simple, Request can be defined It can be defined as /Symfony/Core/Request, or it can be defined as /Symfony/Core/Transport/Request. There can be many sub-namespaces under the /Core namespace. You can define how many layers of namespaces you want.
#4. When loading from the file system, the separator character (/) of each namespace must be converted to DIRECTORY_SEPARATOR (OS path separator)
#Now we finally come to the mapping specification. The / symbol of the namespace must be converted into a path separator, which means that the namespace /Symfony/Core/Request must be converted into a directory structure such as SymfonyCoreRequest.
-
5. In the class name, each underscore _ symbol should be converted into DIRECTORYSEPARATOR (operating system path separator). In a namespace, the underscore symbol has no (special) meaning.
This sentence means that if our namespace is /Symfony/Core/Request_a, then we should map it to a directory like SymfonyCoreRequesta. Why is there such a provision? This is because there was no namespace before PHP5, and programmers could only name it Symfony_Core_Request_a. This provision of PSR0 is to be compatible with this situation.
The remaining two are very simple and will not be mentioned.
With such namespace naming rules and mapping standards, we can reason about where we should put the files where the namespace is located. Still taking Symfony/Core/Request as an example, its directory is /path/to/project/vendor/Symfony/Core/Request.php, where /path/to/project is the location of your project on the disk, /path/to /project/vendor is the directory where all third-party libraries used by the project are located. /path/to/project/vendor/Symfony is the directory corresponding to the top-level namespace/Symfony. The file directories below are established according to the PSR0 standard:
/Symfony/Core/Request => /Symfony/Core/Request.php
Everything is perfect, right? No, there are still some flaws:
Should we still be compatible without namespaces?
According to the PSR0 standard, the namespace /A/B/C/D/E/F must correspond to a directory structure /A/B/C/D/ E/F, is this directory structure too deep?
At the end of 2013, the fifth new standard was released Specification - PSR-4.
PSR-4 specifies how to specify a file path to automatically load class definitions, and also specifies the location of automatically loaded files. At first glance, this looks similar to the PSR-0. In fact, it does have some overlap in functionality. The difference is that the PSR-4 specification is relatively clean, removing content that is compatible with previous versions of PHP 5.3, and feels a bit like an upgraded version of PSR-0. Of course, PSR-4 is not intended to completely replace PSR-0, but to supplement PSR-0 when necessary - of course, PSR-4 can also replace PSR-0 if you like. PSR-4 can be used with other autoloading mechanisms including PSR-0.
The difference between the PSR4 standard and the PSR0 standard:
在类名中使用下划线没有任何特殊含义。
命名空间与文件目录的映射方法有所调整。
对第二项我们详细解释一下 ( Composer自动加载的原理):
假如我们有一个命名空间:Foo/class,Foo 是顶级命名空间,其存在着用户定义的与目录的映射关系:
<span style="font-size: 16px;">"Foo/" => "src/"<br/></span>
按照PSR0标准,映射后的文件目录是: src/Foo/class.php,但是按照 PSR4 标准,映射后的文件目录就会是:src/class.php,为什么要这么更改呢?原因就是怕命名空间太长导致目录层次太深,使得命名空间和文件目录的映射关系更加灵活。
再举一个例子,来源 PSR-4——新鲜出炉的PHP规范:
PSR-0风格
<span style="font-size: 16px;"> vendor/<br> vendor_name/<br> package_name/<br> src/<br> Vendor_Name/<br> Package_Name/<br> ClassName.php # Vendor_Name\Package_Name\ClassName<br> tests/<br> Vendor_Name/<br> Package_Name/<br> ClassNameTest.php # Vendor_Name\Package_Name\ClassName<br></span>
PSR-4风格
<span style="font-size: 16px;"> vendor/<br> vendor_name/<br> package_name/<br> src/<br> ClassName.php # Vendor_Name\Package_Name\ClassName<br> tests/<br> ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest<br></span>
对比以上两种结构,明显可以看出PSR-4带来更简洁的文件结构。
The above is the detailed content of Detailed explanation of PHP’s automatic loading function. For more information, please follow other related articles on the PHP Chinese website!