分析
- 上一节把register第五步分析了 这一节我们分析第一步和第二步
我还是把源码附上
public static function register($autoload = '')
{
// 【1】注册系统自动加载
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
$rootPath = self::getRootPath();
self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;
// 【2】Composer自动加载支持
if (is_dir(self::$composerPath)) {
if (is_file(self::$composerPath . 'autoload_static.php')) {
require self::$composerPath . 'autoload_static.php';
// require $rootPath.'extend/Liangzai.php';
$declaredClass = get_declared_classes();
$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);
}
}
// 【3】注册命名空间定义
// 【4】加载类库映射文件
// 【5】自动加载extend目录
}
- 【2】Composer自动加载支持
- 这一步没有什么可说的直接加载Composer 但是建议看一下 Composer加载源码 深入解析 composer 的自动加载原理
- 【1】注册系统自动加载
历经这么多最终跳到 findFile
spl_autoload_register()---->autoload()–>findFile();
- autoload()
- 【1】找出返回注册的别名
- 【2】查找文件
// 自动加载
public static function autoload($class)
{
//【1】找出返回注册的别名
if (isset(self::$classAlias[$class])) {
return class_alias(self::$classAlias[$class], $class);
}
//【2】查找文件
if ($file = self::findFile($class)) {
// Win环境严格区分大小写
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
__include_file($file);
return true;
}
}
- findFile()
- 【1】类库映射
- 【2】查找 PSR-4
- 【3】 查找 PSR-4 fallback dirs
- 【4】 查找 PSR-0
- 【5】查找 PSR-0 fallback dirs
private static function findFile($class)
{
// 【1】类库映射
if (!empty(self::$classMap[$class])) {
return self::$classMap[$class];
}
// 【2】查找 PSR-4
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
$first = $class[0];// 例如 traits t 取出第一个字母
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 . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// 【3】 查找 PSR-4 fallback dirs
foreach (self::$fallbackDirsPsr4 as $dir) {
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// 【4】 查找 PSR-0
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
}
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 . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// 【5】查找 PSR-0 fallback dirs
foreach (self::$fallbackDirsPsr0 as $dir) {
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
return self::$classMap[$class] = false;
}
总结
第二步【2】大家都知道这个函数spl_autoload_register ,一个懒加载的过程,发现找不到类的时候都会跑到这个函数去,他会自动加载,我们的回调函数里面利用了一系列的属性,这些属性,怎么设置的要搞清楚,之所以把这一步放到最后分析,有了前面的分析这一步就是取的过程。