PSR-4 自动加载标准
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 12 课,共 91 课。
PSR-4 是一项标准,它规定了如何根据命名空间和文件位置自动加载 PHP 类。你不必手动引入每个类文件,使用类时,PSR-4 会让 PHP 自动查找并加载它们。
核心规则很简单:命名空间必须与目录结构匹配。如果你有一个类 App\Models\User,文件应位于 App/Models/User.php。
<?php
// 文件:src/Models/User.php
namespace App\Models;
class User {
public $name;
public function __construct($name) {
$this->name = $name;
}
}
你可以编写一个遵循 PSR-4 规则的简单自动加载函数:
<?php
// 文件:autoload.php
spl_autoload_register(function ($class) {
$prefix = 'App\\';
$baseDir = __DIR__ . '/src/';
// 检查类是否使用了我们的命名空间前缀
if (strpos($class, $prefix) === 0) {
$relativeClass = substr($class, strlen($prefix));
$file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) {
require $file;
}
}
});
spl_autoload_register 函数会告诉 PHP,每当遇到未知的类时,就调用你的函数。这个函数会将命名空间转换为文件路径并加载文件。
重点:PSR-4 在命名空间和文件路径之间建立了可预测的映射。看到 App\Models\User 时,你马上就知道文件位于 src/Models/User.php。这项约定让项目更容易浏览和维护。
挑战
简单让我们构建一个简单的 PSR-4 自动加载系统,根据类的命名空间和文件位置自动加载类。
你将创建一个包含 3 个文件的项目,演示 PSR-4 如何将命名空间映射到目录路径:
src/Services/Logger.php:在App\Services命名空间中定义一个Logger类。它应包含一个public $name属性、一个接收并设置名称的构造函数,以及一个返回"[name] logged: [message]"的log($message)方法。src/Services/Mailer.php:在App\Services命名空间中定义一个Mailer类。它应包含一个public $sender属性、一个接收并设置发件人的构造函数,以及一个返回"Mail from [sender] to [to]"的send($to)方法。main.php:使用spl_autoload_register创建一个 PSR-4 自动加载器,将App\命名空间前缀映射到src/目录。自动加载器应将命名空间分隔符转换为目录分隔符,并添加.php以找到正确的文件。注册自动加载器后,使用use关键字导入两个类,然后创建名称为"FileLogger"的Logger,以及发件人为"admin@site.com"的Mailer。输出对日志记录器调用log("System started")的结果,以及对邮件程序调用send("user@example.com")的结果(各占一行)。
关键点在于,自动加载器函数会接收完全限定的类名(例如 App\Services\Logger),并且必须将其转换为文件路径(src/Services/Logger.php)。使用 strpos 检查类名是否以你的命名空间前缀开头,使用 substr 获取相对类名,并使用 str_replace 将反斜杠转换为正斜杠。
亲手试试
<?php
// PSR-4 自动加载器的实现
// TODO:使用 spl_autoload_register 注册自动加载器
// 自动加载器应执行以下步骤:
// 1. 检查类名是否以命名空间前缀 'App\' 开头
// 2. 移除前缀 'App\',得到相对类名
// 3. 将命名空间分隔符(\)转换为目录分隔符(/)
// 4. 在前面加上 'src/',在后面加上 '.php',构建文件路径
// 5. 如果文件存在,就加载它
spl_autoload_register(function ($class) {
// TODO:定义命名空间前缀和基础目录
// TODO:检查类名是否使用该命名空间前缀(使用 strpos)
// TODO:获取相对类名(使用 substr)
// TODO:将 \ 替换为 /,构建文件路径(使用 str_replace)
// TODO:如果文件存在,就引入它
});
// TODO:使用 'use' 关键字导入 Logger 和 Mailer 类
// TODO:创建一个名称为 "FileLogger" 的 Logger 实例
// TODO:创建一个发件人为 "admin@site.com" 的 Mailer 实例
// TODO:输出 log("System started") 的结果
// TODO:输出 send("user@example.com") 的结果
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器