thinkphp5框架實現原理二 自動載入(簡易版)
阿新 • • 發佈:2019-01-22
一、在base.php中 \core\Loader::register();
載入自動載入
/**
* @param null $autoload
* 自動載入
*/
public static function register($autoload = null) {
// 註冊系統自動載入(核心目錄Loader的autoload方法)
spl_autoload_register($autoload ?: '\core\\Loader::autoload', true, true);
// 註冊名稱空間定義(註冊核心目錄名稱空間)
self::addNamespace([
'core' => ROOT_PATH . 'core' . DS,
]);
}
二、核心目錄Loader的autoload方法
/**
* 自動載入
* @access public
* @param string $class 類名
* @return bool
*/
public static function autoload($class) {
// 檢測命名空間別名
if (!empty(self::$namespaceAlias)) {
$namespace = dirname($class);
if (isset(self::$namespaceAlias[$namespace])) {
$original = self::$namespaceAlias[$namespace] . '\\' . basename($class);
if (class_exists($original)) {
return class_alias($original , $class, false);
}
}
}
//查詢類檔案是否存在
if ($file = self::findFile($class)) {
// 非 Win 環境不嚴格區分大小寫
if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) {
//引入檔案
__include_file($file);
return true;
}
}
return false;
}
三、查詢類檔案是否存在
/**
* 查詢檔案
* @access private
* @param string $class 類名
* @return bool|string
*/
private static function findFile($class) {
// 類庫對映
if (!empty(self::$classMap[$class])) {
return self::$classMap[$class];
}
// 查詢 PSR-4(將名稱空間轉換為路徑【core\Config轉換為core/Config.php】)
$logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
$first = $class[0];
if (isset(self::$prefixLengthsPsr4[$first])) {
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// 查詢 PSR-4 fallback dirs
foreach (self::$fallbackDirsPsr4 as $dir) {
if (is_file($file = $dir . DS . $logicalPathPsr4)) {
return $file;
}
}
// 查詢 PSR-0
if (false !== $pos = strrpos($class, '\\')) {
// namespace class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DS) . EXT;
}
if (isset(self::$prefixesPsr0[$first])) {
foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (is_file($file = $dir . DS . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// 查詢 PSR-0 fallback dirs
foreach (self::$fallbackDirsPsr0 as $dir) {
if (is_file($file = $dir . DS . $logicalPathPsr0)) {
return $file;
}
}
// 找不到則設定對映為 false 並返回
return self::$classMap[$class] = false;
}
四、引入類檔案
/**
* 引入檔案
* @param string $file 檔案路徑
* @return mixed
*/
function __include_file($file) {
return include $file;
}
五、載入核心目錄名稱空間【core】
self::addNamespace([ 'core' => ROOT_PATH . 'core' . DS,]);
/**
* 註冊名稱空間
* @access public
* @param string|array $namespace 名稱空間
* @param string $path 路徑
* @return void
*/
public static function addNamespace($namespace, $path = '') {
if (is_array($namespace)) {
foreach ($namespace as $prefix => $paths) {
//新增 PSR-4 空間【core\, __ROOT__/core】
self::addPsr4($prefix . '\\', rtrim($paths, DS), true);
}
} else {
//新增 PSR-4 空間
self::addPsr4($namespace . '\\', rtrim($path, DS), true);
}
}
新增 PSR-4 空間
/**
* 新增 PSR-4 空間
* 把名稱空間對映新增到名稱空間裡【array(1) { ["core\"]=> array(1) { [0]=> "__ROOT__/core" } }】
* @access private
* @param array|string $prefix 空間字首
* @param string $paths 路徑
* @param bool $prepend 預先設定的優先順序更高
* @return void
*/
private static function addPsr4($prefix, $paths, $prepend = false) {
if (!$prefix) {
// Register directories for the root namespace.
self::$fallbackDirsPsr4 = $prepend ?
array_merge((array)$paths, self::$fallbackDirsPsr4) :
array_merge(self::$fallbackDirsPsr4, (array)$paths);
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException(
"A non-empty PSR-4 prefix must end with a namespace separator."
);
}
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
self::$prefixDirsPsr4[$prefix] = (array)$paths;
} else {
self::$prefixDirsPsr4[$prefix] = $prepend ?
// Prepend directories for an already registered namespace.
array_merge((array)$paths, self::$prefixDirsPsr4[$prefix]) :
// Append directories for an already registered namespace.
array_merge(self::$prefixDirsPsr4[$prefix], (array)$paths);
}
}