designModeDemo/bin/Psr4Autoload.php

143 lines
4.3 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace bin;
class Psr4Autoload
{
/**
* 关联数组,键名为命名空间前缀,键值为一个基本目录数组。
*
* @var array
*/
protected array $prefixes = [];
/**
* 通过 SPL 自动加载器栈注册加载器
*
* @return void
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
$this->addNamespace('bin', ROOTDIR . DIRECTORY_SEPARATOR . 'bin', true);
$this->addNamespace('demo', ROOTDIR . DIRECTORY_SEPARATOR . 'demo', true);
}
/**
* 为命名空间前缀添加一个基本目录
*
* @param string $prefix 命名空间前缀。
* @param string $base_dir 命名空间下类文件的基本目录
* @param bool $prepend 如果为真,预先将基本目录入栈
* 而不是后续追加;这将使得它会被首先搜索到。
* @return void
*/
public function addNamespace(string $prefix, string $base_dir, bool $prepend = false)
{
// 规范化命名空间前缀
$prefix = trim($prefix, '\\') . '\\';
// 规范化尾部文件分隔符
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
// 初始化命名空间前缀数组
if (isset($this->prefixes[ $prefix ]) === false) {
$this->prefixes[ $prefix ] = array();
}
// 保留命名空间前缀的基本目录
if ($prepend) {
array_unshift($this->prefixes[ $prefix ], $base_dir);
} else {
array_push($this->prefixes[ $prefix ], $base_dir);
}
}
/**
* 加载给定类名的类文件
*
* @param string $class 合法类名
* @return string|bool 成功时为已映射文件名,失败则为 false
*/
public function loadClass(string $class)
{
// 当前命名空间前缀
$prefix = $class;
// 通过完整的命名空间类名反向映射文件名
while (false !== $pos = strrpos($prefix, '\\')) {
// 在前缀中保留命名空间分隔符
$prefix = substr($class, 0, $pos + 1);
// 其余的是相关类名
$relative_class = substr($class, $pos + 1);
// 尝试为前缀和相关类加载映射文件
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
}
// 删除 strrpos() 下一次迭代的尾部命名空间分隔符
$prefix = rtrim($prefix, '\\');
}
// 找不到映射文件
return false;
}
/**
* 为命名空间前缀和相关类加载映射文件。
*
* @param string $prefix 命名空间前缀
* @param string $relative_class 相关类
* @return string|bool Boolean 无映射文件则为false否则加载映射文件
*/
protected function loadMappedFile(string $prefix, string $relative_class)
{
// 命名空间前缀是否存在任何基本目录
if (isset($this->prefixes[ $prefix ]) === false) {
return false;
}
// 通过基本目录查找命名空间前缀
foreach ($this->prefixes[ $prefix ] as $base_dir) {
// 用基本目录替换命名空间前缀
// 用目录分隔符替换命名空间分隔符
// 给相关的类名增加 .php 后缀
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php';
// 如果映射文件存在,则引入
if ($this->requireFile($file)) {
// 搞定了
return $file;
}
}
// 找不到
return false;
}
/**
* 如果文件存在从系统中引入进来
*
* @param string $file 引入文件
* @return bool 文件存在则 true 否则 false
*/
protected function requireFile(string $file) : bool
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}