Basic introduction of PHP namespace and automatic loading mechanism

  • 2021-12-19 06:23:26
  • OfStack

Preface

include and require are the two basic methods of introducing files in PHP. There is nothing wrong with using include and require directly in small-scale development, but it will cause a large accumulation of include and require in large-scale projects. This kind of code is not elegant, inefficient to execute, and difficult to maintain.

In order to solve this problem, some frameworks will give a configuration list of imported files, and import the required files when the object is initialized. However, this only makes the code simpler, and the effect of introduction is still not satisfactory. After PHP5, with the improvement of PHP object-oriented support, the __autoload function really made automatic loading possible.

* include and require are identical in that include only generates a warning when an error occurs, whereas require throws an error termination script.

* The only difference between include_once and include is that include_once checks whether the file has been imported, and if so, it will not be imported again.

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

The easiest way to implement automatic loading is to use the __autoload magic method. When the required class is not introduced, this function will be triggered before PHP reports an error, and the undefined class name will be passed in as an argument. As for the specific logic of the function, it needs to be implemented by the user himself.

First, create an autoload. php to do a simple test:


//  Class is not defined, the system automatically calls 
function __autoload($class)
{
 /*  Specific processing logic  */
 echo $class;//  Simple output undefined class name 
}

new HelloWorld();

/**
 *  Output  HelloWorld  And error message 
 * Fatal error: Class 'HelloWorld' not found
 */

From this simple example, we can find that during the instantiation of classes, the work done by the system is roughly as follows:


/*  Simulate the instantiation process of the system  */
function instance($class)
{
 //  Returns its instance if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 }
 //  View  autoload  Is the function user-defined 
 if (function_exists('__autoload')) {
  __autoload($class); //  Finally 1 Opportunities for second introduction 
 }
 //  Check again if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 } else { //  System: I really can't help it 
  throw new Exception('Class Not Found');
 }
}

Now that we understand how the __autoload function works, let's use it for auto-loading.

First, create a class file (recommended file name and class name 1), the code is as follows:


class [ClassName] 
{
 //  Output the current class name when the object is instantiated 
 function __construct()
 {
  echo '<h1>' . __CLASS__ . '</h1>';
 }
}

(I've created an HelloWorld class here for demonstration purposes.) Next we'll define the specific logic of __autoload to enable it to load automatically:


function __autoload($class)
{
 //  Determine the file name according to the class name 
 $file = $class . '.php';

 if (file_exists($file)) {
  include $file; //  Introduce PHP Documents 
 }
}

new HelloWorld();

/**
 *  Output  <h1>HelloWorld</h1>
 */

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

Namespaces are not new, and many languages (such as C + +) already support this feature. However, PHP started late and was not supported until PHP 5.3.

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".

Here we will do a small task to introduce Baidu's CEO Li Yanhong:


namespace  Baidu ;

class  Li Yanhong 
{
 function __construct()
 {
  echo ' Founder of Baidu ';
 }
}

↑ This is Li Yanhong's basic information. namespace is his unit logo and class is his name.

Namespaces are declared by the keyword namespace. If a file contains a namespace, it must declare the namespace before all other code.


new  Baidu \ Li Yanhong (); //  Qualified class name 
new \ Baidu \ Li Yanhong (); //  Fully qualified class name 

↑ Under 1 general circumstances, they can understand whether they introduce "Baidu Robin Li" or "Baidu Robin Li" to others.

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, it defaults to global (\).


namespace  Google ;

new  Baidu \ Li Yanhong (); //  Google \ Baidu \ Li Yanhong (actual result) 
new \ Baidu \ Li Yanhong (); //  Baidu \ Li Yanhong (actual result) 

If you introduce Li Yanhong to their employees in Google, 1 must indicate that it is "Li Yanhong of Baidu Company". Otherwise, he would think Baidu is a department of Google, and Li Yanhong is only one of its employees.

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  Baidu \ Li Yanhong ;
new  Li Yanhong (); //  Baidu \ Li Yanhong (actual result) 

/*  Setting Alias  */
use  Baidu \ Li Yanhong  AS CEO;
new CEO(); //  Baidu \ Li Yanhong (actual result) 

/*  In any case  */
new \ Baidu \ Li Yanhong ();//  Baidu \ Li Yanhong (actual result) 

The first case is that others already know Li Yanhong. You only need to say your name directly, and he can know who you mean. The second case is that Li Yanhong is their CEO. If you say CEO directly, he can react immediately.

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 function and passes in the qualified class name as an argument before the "Class Not Found" error is thrown.

Therefore, the above examples are all based on the fact that you have manually introduced relevant files, otherwise the system will throw out "Class 'Baidu\ Robin Li' not found".

=================spl_autoload==================

Next, let's implement automatic loading with namespaces. Here we use the spl_autoload_register () function, which requires your PHP version number greater than 5.12.

The function spl_autoload_register registers the passed-in function (arguments can be in the form of callback functions or function names) in the SPL __autoload function queue and removes the system default __autoload () function.

1 Once the spl_autoload_register () function is called, when an undefined class is called, all functions registered with the spl_autoload_register () function are called in sequence instead of calling the __autoload () function automatically.

Now, let's create an Linux class that uses os as its namespace (it is recommended that the file name and class name remain 1):


namespace os; //  Namespace 

class Linux //  Class name 
{
 function __construct()
 {
  echo '<h1>' . __CLASS__ . '</h1>';
 }
}

Then, create a new PHP file in the same directory, and use spl_autoload_register to realize automatic loading by function callback:


spl_autoload_register(function ($class) { // class = os\Linux

 /*  Qualified class name path mapping  */
 $class_map = array(
  //  Qualified class name  =>  File path 
  'os\\Linux' => './Linux.php',
 );

 /*  Determine the file name according to the class name  */
 $file = $class_map[$class];

 /*  Introduce related documents  */
 if (file_exists($file)) {
  include $file;
 }
});

new \os\Linux();

Here we use an array to hold the relationship between the class name and the file path, so that when the class name is passed in, the auto-loader knows which file to import to load the class.

However, if there are more 1-denier files, the mapping array will become very long, which will be quite troublesome to maintain. If the naming can comply with the conventions of Unification 1, the auto loader can automatically resolve and determine the path where the class file is located. PSR-4, which will be introduced next, is a widely adopted convention.

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

PSR-4 is a related specification about automatically loading corresponding classes from file paths. The specification stipulates that a fully qualified class name needs to have the following structure:

\ < Top-level namespace > (\ < Child namespace > )*\ < Class name >

If you continue to use the above example as an analogy, the top-level namespace is equivalent to the company, the child namespace is equivalent to the position, and the class name is equivalent to the person name. Then Li Yanhong's standard name is "Baidu CEO Li Yanhong".

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\ app\ view\ news\ Index, if app stands for C:\ Baidu, the path to this class is C:\ Baidu\ view\ news\ Index. php

Let's take parsing\ app\ view\ news\ Index as an example and write a simple Demo:


/*  Simulate the instantiation process of the system  */
function instance($class)
{
 //  Returns its instance if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 }
 //  View  autoload  Is the function user-defined 
 if (function_exists('__autoload')) {
  __autoload($class); //  Finally 1 Opportunities for second introduction 
 }
 //  Check again if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 } else { //  System: I really can't help it 
  throw new Exception('Class Not Found');
 }
}
0

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, in the directory\ app\ mvc\ view\ home:


/*  Simulate the instantiation process of the system  */
function instance($class)
{
 //  Returns its instance if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 }
 //  View  autoload  Is the function user-defined 
 if (function_exists('__autoload')) {
  __autoload($class); //  Finally 1 Opportunities for second introduction 
 }
 //  Check again if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 } else { //  System: I really can't help it 
  throw new Exception('Class Not Found');
 }
}
1

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


/*  Simulate the instantiation process of the system  */
function instance($class)
{
 //  Returns its instance if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 }
 //  View  autoload  Is the function user-defined 
 if (function_exists('__autoload')) {
  __autoload($class); //  Finally 1 Opportunities for second introduction 
 }
 //  Check again if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 } else { //  System: I really can't help it 
  throw new Exception('Class Not Found');
 }
}
2

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


include 'Loader.php'; //  Introducing loader 
spl_autoload_register('Loader::autoload'); //  Register auto-load 

new \app\mvc\view\home\Index(); //  Instantiate an unreferenced class 

/**
 *  Output : <h1> Welcome To Home </h1>
 */

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.

At this point, the principle of auto-loading has been all said, if you are interested in further understanding, you can refer to the following ThinkPHP source code.


/*  Simulate the instantiation process of the system  */
function instance($class)
{
 //  Returns its instance if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 }
 //  View  autoload  Is the function user-defined 
 if (function_exists('__autoload')) {
  __autoload($class); //  Finally 1 Opportunities for second introduction 
 }
 //  Check again if the class exists 
 if (class_exists($class, false)) {
  return new $class();
 } else { //  System: I really can't help it 
  throw new Exception('Class Not Found');
 }
}
4

Summarize


Related articles: