php的自动加载和命名空间

臭大佬 2020-10-31 11:42:38 182
php 
简介 php的自动加载和命名空间

__autoload

魔术变量 __autoload():当需要使用的类没有被引入时,这个函数会在PHP报错前被触发,未定义的类名会被当作参数传入。

注意:Warning
本特性已自 PHP 7.2.0 起废弃。强烈建议不要使用本特性。
见官方文档- https://www.php.net/manual/zh/function.autoload.php

本地调用会报如下错误,Deprecated: __autoload() is deprecated, use spl_autoload_register() instead in XXX

所以,PHP 版本号大于 5.12,都可以使用spl_autoload_register 函数来代替。

命名空间

命名空间是为了解决命名冲突的问题。
使用命名空间只是让类名有了前缀,不容易发生冲突,系统仍然不会进行自动导入。

spl_autoload

一旦调用 spl_autoload_register() 函数,当调用未定义类时,系统就会按顺序调用注册到 spl_autoload_register() 函数的所有函数,而不是自动调用 __autoload() 函数。

PSR-4规范

PSR-4 是关于由文件路径自动载入对应类的相关规范,规范规定了一个完全限定类名需要具有以下结构:

\<顶级命名空间>(\<子命名空间>)*\<类名>

PSR-4 规范中必须要有一个顶级命名空间,它的意义在于表示某一个特殊的目录(文件基目录)。子命名空间代表的是类文件相对于文件基目录的这一段路径(相对路径),类名则与文件名保持一致(注意大小写的区别)。

demo

我们来实现以下自动加载功能。目录结构如下:

demo
….one
……..a.php
….two
……..a.php
….verdor
……..Loader.php
index.php

代码如下:
demo/one/a.php

<?php
namespace app\one;

class A
{
    // 对象实例化时输出当前类名
    function __construct()
    {
        echo 'one/' . __CLASS__;
        echo "\r\n";
    }
}

demo/two/a.php

<?php
namespace app\two;

class A
{
    // 对象实例化时输出当前类名
    function __construct()
    {
        echo 'two/' . __CLASS__;
        echo "\r\n";
    }
}

自动加载文件:demo/verdor/Loader.php

<?php

class Loader
{
    /**
     * 路径映射
     */
    public static $vendorMap = array(
        'app' => __DIR__ . DIRECTORY_SEPARATOR . '..',
    );

    /**
     * 自动加载器
     */
    public static function autoload($class)
    {
        $file = self::findFile($class);
        if (file_exists($file)) {
            self::includeFile($file);
        }
    }

    /**
     * 解析文件路径
     */
    private static function findFile($class)
    {
        $vendor = substr($class, 0, strpos($class, '\\')); // 顶级命名空间
        $vendorDir = self::$vendorMap[$vendor]; // 文件基目录
        $filePath = substr($class, strlen($vendor)) . '.php'; // 文件相对路径
        return strtr($vendorDir . $filePath, '\\', DIRECTORY_SEPARATOR); // 文件标准路径
    }

    /**
     * 引入文件
     */
    private static function includeFile($file)
    {
        if (is_file($file)) {
            include $file;
        }
    }
}

入口文件 demo/index.php

<?php

namespace app;
// 引入加载器
include './verdor/Loader.php'; 
// 注册自动加载
spl_autoload_register('Loader::autoload'); 

new one\A();

new two\A();

在demo目录下运行:

php index.php

one/app\one\A
two/app\two\A

这样我们就实现了自动加载。