Namespace and Automatic Loading Method of php

  • 2021-12-19 06:24:36
  • OfStack

Automatic loading of classes

Introduction

When we load a class in the php code, we must have a class file of include or require.

However, similar situations are encountered, such as:


require "Class1.php";
require "Class2.php";
$boy = $_GET['sex'] = 0?true:false;
if($boy)
{
 $class1 = new Class1();
}else{
 $class2 = new Class2();
}

If we need to determine the gender of a person, instantiate the class class1 if it is male, and instantiate the class class2 if it is female. Here's the problem: In this code, I only need to execute one instantiation object at a time, but I have to load these two class files.

php provides a solution to this problem

spl_auto_register()

This concept was introduced in php 5.1


spl_auto_register($autoload_function = null, $throw = true, $prepend = false)

The function takes three arguments

autoload_function This is the name of a function "method", which can be a string or an array (used for calling class methods). The function (method) is to include include (requeire) in the class file that requires new, so that the file will not be lost when new. In fact, it is the include and require functions that encapsulate the whole project.

$throw This parameter specifies whether spl_autoload_register () should throw an exception when autoload_function cannot be registered.

If it is true, then spl_autoload_register () will come before the auto-load into the file, and from time to time after it.

Usage

So after having this function, I wrote it like this


function load($class)
{
 require "./{$class}.php";
}
spl_autoload_register('load');
if($boy)
{
 $class1 = new Class1();
}else{
 $class2 = new Class2();
}

The program execution process is as follows:

//Normal process
new 1 object-- > Object not found-- > Report an error

//After the introduction of spl_autoload_register
new 1 object-- > Object not found-- > spl_autoload_register said to me to try-- > Load succeeded

After loading, we executed the function load, and through the splicing of class, we completed the process of loading the function

__autoload()

Auto-loading of classes was discussed earlier when we talked about spl_autoload_register. Today we talk about another kind
__autoload () is no longer recommended in php 7

The __autoload function of php is a magic function. Before this function appeared, if 100 objects were referenced in an php file, then this file needed to introduce 100 class files using include or require, which would lead to the huge php file. So there is this __autoload function.

When is the __autoload function called? When the php file uses the new keyword to instantiate an object, if the class is not defined in this php file, the __autoload function will be triggered. At this time, the php file defining the class can be introduced, and then the instantiation is successful.

(Note: The __autoload function will not be triggered if the object to be instantiated has a definition of the class found in this file.)

The difference between him and spl_autoload_registe r is that when __autoload and spl_autoload_register appear in the file at the same time, spl_autoload_register shall prevail

Namespace

We talked about automatic loading of classes earlier, and then I was thinking about it.

When we write code with the framework, every time we call other classes in another file,

We didn't write the method spl_autoload_register? So how did we achieve it?

Principle

It turns out that we php introduced the concept of namespace in 5.3 (which is why most frameworks do not support versions before 5.3). Namespace is still known to everyone: If you don't know it, you have to think about it in the corner

Namespace is simply an identity, and its main purpose is to solve the problem of naming conflicts. Just like in daily life, there are many people with the same name. How to distinguish these people? Then you need to add one extra logo. It seems good to regard the work unit as a logo, so that you don't have to worry about the embarrassment of "bumping into your name".

Namespace classification

Fully qualified namespace Qualified namespace

new  Chengdu \ Xu Dashuai (); //  Qualified class name 
new \ Chengdu \ Xu Dashuai (); //  Fully qualified class name 

A qualified class name and a fully qualified class name are equivalent when the current namespace is not declared. Because if no space is specified, the default is global ().


namespace  United States ;

new  Chengdu \ Xu Dashuai (); //  United States \ Chengdu \ Xu Dashuai (actual result) 
new \ Chengdu \ Xu Dashuai (); //  Chengdu \ Xu Dashuai (actual result) 

This example shows the difference between using qualified class names and fully qualified class names under namespaces. (Fully qualified class name = current namespace + qualified class name)


/*  Import Namespace  */
use  Chengdu \ Xu Dashuai ;
new  Xu Dashuai (); //  Chengdu \ Xu Dashuai (actual result) 

/*  Setting Alias  */
use  Chengdu \ Xu Dashuai  AS CEO;
new CEO(); //  Chengdu \ Xu Dashuai (actual result) 

/*  In any case  */
new \ Chengdu \ Xu Dashuai ();//  Chengdu \ Xu Dashuai (actual result) 

Using namespaces only prefixes class names, which are not prone to conflicts, and the system still does not import automatically.

If the file is not imported, the system fires the __autoload () or spl_autoload_register function before the "Class Not Found" error is thrown, passing in the qualified class name as an argument.

The above examples are based on the fact that you have manually introduced relevant files, otherwise the system will throw out "Class 'Chengdu Xu Dashuai' not found". Because she doesn't know where this file is. So automatic loading was introduced after namespaces were introduced

Next, we are loading our class with the namespace

A small experiment to automatically load classes using namespaces

First, we define in a new file


//School.php
namespace top;

class School
{
 function __construct()
 {
 echo ' This is '.__CLASS__.' Implementation of the ';
 }
}

This is certainly not important, what is important is that we call his function. We create an index. php file in the same directory (different files are OK, as long as you write the mapping relationship)


//index.php

spl_autoload_register(function ($class){
 // From our  class Find in the name, is there a corresponding path 
 $map = [
 'top\\School'=>'./School.php'
 ];

 $file = $map[$class];
 // Check whether the corresponding file exists 
 if (file_exists($file))
 include $file;
});
echo " Begin <br/>";
new top\School();

Results

Begin
This is the implementation of the top\ School class

We use the mapping relationship between class name and class address to realize our automatic loading. However, this also means that every time we add a file, we must update our mapping file. In a large system, the mapping relationship maintained by such arrays is undoubtedly troublesome. So is there a better way?

PSR4 Automatic Loading Specification

Children's shoes that don't know can be seen here

PSR4 Chinese Document

Specific Explanation of PSR4

The following is an excerpt from the above link, which I think has been thoroughly explained in the above two articles


\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>

There must be a top-level namespace in the PSR-4 specification, which means to represent a special directory (file base directory). The sub-namespace represents the 1 path (relative path) of the class file relative to the file base directory, while the class name and the file name remain 1 (pay attention to the difference between case and case).

For example, in the fully qualified class name appviewnewsIndex, if app stands for C: Baidu, then the path of this class is C: BaiduviewnewsIndex. php

Let's take parsing appviewnewsIndex as an example and write a simple Demo:


$class = 'app\view\news\Index';

/*  Top-level namespace path mapping  */
$vendor_map = array(
 'app' => 'C:\Baidu',
);

/*  The parsing class name is file path  */
$vendor = substr($class, 0, strpos($class, '\\')); //  Take out the top-level namespace [app]
$vendor_dir = $vendor_map[$vendor]; //  File base directory [C:\Baidu]
$rel_path = dirname(substr($class, strlen($vendor))); //  Relative path [/view/news]
$file_name = basename($class) . '.php'; //  Filename [Index.php]

/*  Path of output file  */
echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;

From this Demo, we can see the process of converting qualified class names into paths. Now let's implement the auto-loader in a standard object-oriented way.

First we create a file Index. php, which is in the appmvcviewhome directory:


spl_auto_register($autoload_function = null, $throw = true, $prepend = false)
0

Next, we are creating a load class (no namespace is required), which is in the directory:


spl_auto_register($autoload_function = null, $throw = true, $prepend = false)
1

Finally, register autoload in the Loader class into the spl_autoload_register function:


spl_auto_register($autoload_function = null, $throw = true, $prepend = false)
2

The code in the example is actually a simplified version of the source code of ThinkPHP auto-loader, which is the key to the lazy loading of ThinkPHP 5.

Summarize


Related articles: