Analysis of PHP classes automatically load and namespace

php is to use require (require_once) and include (include_once) keyword loaded class files. But in the actual development projects we are basically not going to use these keywords to load classes. Because doing so would make maintenance of the code is quite difficult. The actual development, we will use the use keyword class, and then direct this new class in the beginning of the file on it. As for how the class is loaded, or composer are generally framework to achieve.

<?php

use Illuminate\Container\Container;

$container = new Container();

Automatically load

Novel site https://www.198200.com

We can by some pseudo-code to simulate what instantiate class engineering class is how it works

function instance($class)
{
    // 如果类已加载则返回其实例
    if (class_exists($class, false)) {
        return new $class();
    }
    // 查看 autoload 函数是否被用户定义
    if (function_exists('__autoload')) {
        __autoload($class); // 最后一次加载类的机会
    }
    // 再次检查类是否存在
    if (class_exists($class, false)) {
        return new $class();
    } else { // 系统:我实在没辙了
        throw new Exception('Class Not Found');
    }
}

php provided in the language level ** __ autoload ** magic method to achieve the user to automatically load their own logic. When users go to new time a class if the class is not loaded , php will be called before throwing error ** __ autoload method to load the class. The following examples of __autoload ** method is simply to load the output of the class name, and did not go to the actual load corresponding to the class, it will throw an error.

<?php

use Illuminate\Container\Container;

$container = new Container();

function __autoload($class)
{
    /* 具体处理逻辑 */
    echo $class;// 简单的输出要加载类的名称
}

/**
 *
运行结果
Illuminate\Container\Container
Fatal error: Uncaught Error: Class 'Illuminate\Container\Container' not found in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php:5
Stack trace:
#0 {main}
  thrown in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php on line 5
 */

After understand ** __ autoload ** function works, let's use it to implement a simple load automatically. We have index.php and Person.php in the same directory as the two files.

//index.php
<?php
function __autoload($class)
{
    // 根据类名确定文件名
    $file = './'.$class . '.php';
    if (file_exists($file)) {
        include $file; // 引入PHP文件
    }
}
new Person();

/*---------------------分割线-------------------------------------*/

//Person.php
class Person
{
    // 对象实例化时输出当前类名
    function __construct()
    {
        echo '<h1>' . __CLASS__ . '</h1>';
    }
}

/**运行结果
 * 输出 <h1>Person</h1>
 */

Namespaces

What matters namespace is not fresh, many languages have long supported this feature (just not the same as it is called), it is mainly a problem to solve is naming conflicts! Just like everyday life, many people will the same name, we have to distinguish their differences through some identification. For example, now we have to use php introduce a man named Joe Smith who, in his finance job. We can describe this.

namespace 财务部门;
 
class 张三
{
    function __construct()
    {
        echo '财务部门的张三';
    }
}

This is the basic information of Joe Smith, namespace is his department identification, class is his name. In this way we can know that he is the finance department of Joe Smith , rather than the engineering department of Joe Smith .

Unqualified name, name and define the fully qualified name

1. Non-qualified name , or does not contain a prefix name of the class , for example, $ comment = new Comment (); if the current namespace is Blog \ Article This article was , it Comment will be resolved, \ Blog \ Article This article was \ it Comment . If you use the Comment code does not contain code (in any namespace in the global space ), the Comment will be parsed as \ Comment .

Note : If the beginning of the file there using the use keyword use one \ two \ Comment; the Comment will be resolved to * * One \ TWO \ Comment **.

2. qualified name, or contains the name prefix , e.g. $ comment = new Article \ Comment ( ); if the current namespace is Blog , the Comment will be parsed as \ Blog \ Article This article was \ Comment . If you use the Comment code does not contain code (in any namespace in the global space ), the Comment will be parsed as \ Article This article was \ Comment .

3. The fully qualified name , or the name with global prefix operator , for example, $ comment = new \ Article \ Comment (); in this case, it Comment always be resolved into \ Article This article was \ it Comment .

spl_autoload

Let's go on to achieve the kind of automatic loading in the case of containing namespace. We use spl_autoload_register () function to achieve, which requires your PHP version number is greater than 5.12 . function spl_autoload_register function is to pass function (parameter can callback function or function name form) registered with the SPL __autoload function queue in, and remove the system default ** __ autoload () ** function. Once spl_autoload_register call () function call when the class is not defined, the system will call order to register spl_autoload_register () function all functions, rather than automatically calls the __autoload ** () ** function.

Now, let's create a Linux class that uses os as its name space (file name suggestion consistent with the class name):

<?php
namespace os; // 命名空间
 
class Linux // 类名
{
    function __construct()
    {
        echo '<h1>' . __CLASS__ . '</h1>';
    }
}

Next, create a index.php file in the same directory, use the callback function spl_autoload_register way to automatically load:

<?php

spl_autoload_register(function ($class) { // class = os\Linux
 
    /* 限定类名路径映射 */
    $class_map = array(
        // 限定类名 => 文件路径
        'os\\Linux' => './Linux.php',
    );
    /* 根据类名确定文件路径 */
    $file = $class_map[$class];
    /* 引入相关文件 */
    if (file_exists($file)) {
        include $file;
    }
});
 
new \os\Linux();

Here we use an array to hold the class name and file path relations, so that when the name of the incoming class, the autoloader will know that the introduction of which file to load the class. But once the document be filed, then the mapping arrays become very long, so it will be very troublesome to maintain. If you can follow a unified naming convention, you can let the autoloader automatically resolves the paths to determine the class file is located. As agreed, next to introduce the PSR-4 is a widely used

PSR-4 specification

PSR-4 is automatically loaded on a file path corresponding to the class of related specifications, the specification of a fully qualified class name need to have the following structure:

<Top-level namespace> (<sub-namespace>) * <class name>

PSR-4 specification must have a top-level namespace , its significance is a representation of a special directory ( file-based directory ). Subnamespaces represents the class file with respect to file directories group this segment of the path (relative path), the class name is the file name is consistent (note the case difference).

For example: the fully qualified class name \ app \ view \ news \ Index , if the app on behalf of C: \ Baidu, then the path of this class is C: \ Baidu \ View \ News \ Index.php . We have to parsing \ app \ view \ news \ Index for example, write a simple Demo:

<?php

$class = 'app\view\news\Index';
 
/* 顶级命名空间路径映射 */
$vendor_map = array(
    'app' => 'C:\Baidu',
);
 
/* 解析类名为文件路径 */
$vendor = substr($class, 0, strpos($class, '\\')); // 取出顶级命名空间[app]
$vendor_dir = $vendor_map[$vendor]; // 文件基目录[C:\Baidu]
$rel_path = dirname(substr($class, strlen($vendor))); // 相对路径[/view/news]
$file_name = basename($class) . '.php'; // 文件名[Index.php]
 
/* 输出文件所在路径 */
echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;

Micro-channel public number -php cultivation of the road

Original articles published 0 · won praise 1 · views 1909

Guess you like

Origin blog.csdn.net/sinat_34560749/article/details/103987431