29
05月
2020
入口文件 public/index.php
<?php // [ 应用入口文件 ] namespace think; // 加载基础文件 require __DIR__ . '/../thinkphp/base.php'; ......
基础文件 thinkphp/base.php
<?php namespace think; // 载入Loader类 require __DIR__ . '/library/think/Loader.php'; // 注册自动加载 Loader::register(); ......
自动加载类 thinkphp/library/think/Loader.php
......
// 注册自动加载机制
public static function register($autoload = '')
{
/*
spl_autoload_register函数是实现自动加载未定义类功能的的重要方法,当new一个未事先引入的不存在的类时,自动调用该方法
PHP碰到没有定义的类就执行think\\Loader::autoload()
spl_autoload_register有三个参数
autoload_function
欲注册的自动装载函数。如果没有提供任何参数,则自动注册 autoload 的默认实现函数spl_autoload()。
throw
此参数设置了 autoload_function 无法成功注册时, spl_autoload_register()是否抛出异常。
prepend
如果是 true,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。
*/
// 注册系统自动加载
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
// 获取根目录路径
$rootPath = self::getRootPath();
// 获取composer目录路径
self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;
// Composer自动加载支持
if (is_dir(self::$composerPath)) {
if (is_file(self::$composerPath . 'autoload_static.php')) {
require self::$composerPath . 'autoload_static.php';
// 返回当前脚本中已定义的类名组成的数组(自定义类、系统内置类)
$declaredClass = get_declared_classes();
// 取出上面数组中最后一个类,即上面引入的 autoload_static.php 中的类
$composerClass = array_pop($declaredClass);
foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {
if (property_exists($composerClass, $attr)) {
self::${$attr} = $composerClass::${$attr};
}
}
} else {
self::registerComposerLoader(self::$composerPath);
}
}
// 注册命名空间定义
self::addNamespace([
'think' => __DIR__,
'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',
]);
// 类的映射键值对,需手动生成(php think optimize:autoload)才有这个文件
// 可提升性能
// 加载类库映射文件
if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
}
// 自动加载extend目录, 添加类自动加载的目录
self::addAutoLoadDir($rootPath . 'extend');
// 如果需要添加多个自动加载目录,可以多次调用此方法
// self::addAutoLoadDir($rootPath . 'other');
}
// 自动加载
public static function autoload($class)
{
if (isset(self::$classAlias[$class])) {
// 设置类的别名 如 /Users/wenbinzhao/Documents/dnmp/www/tp5/thinkphp/library/think/Env.php 设为 think\Env
// 使用的类的时候就可以直接使用别名 think\Env
return class_alias(self::$classAlias[$class], $class);
}
// 通过命名空间查找自动加载类的文件路径
if ($file = self::findFile($class)) {
// Win环境严格区分大小写
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
// 通过 include 引入文件
__include_file($file);
return true;
}
}
......总结
类的自动加载,其实就是先绑定了自动加载函数,然后在类的属性上面定义了一系列的映射关系,然后在自动加载函数中通过命名空间/类名参数查询映射关系,将映射的目录include引入的操作