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
这样我们就实现了自动加载。