composer的第三方类库自动加载,其实就是将第三方类库的完整路径保存在Loader类的静态属性中,以Psr4为例
1.thinkphp\base.php
// 载入Loader类
require __DIR__ . '/library/think/Loader.php';
// 注册自动加载
Loader::register();
2.think\Loader(Loader::register())
// 注册自动加载机制
public static function register($autoload = '')
{
// 注册系统自动加载
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
...
self::registerComposerLoader(self::$composerPath);
注:spl_autoload_register—注册给定的函数作为 __autoload 的实现,这里是将think\\Loader::autoload注册为__autoload 的实现.
3.self::registerComposerLoader
// 注册composer自动加载
public static function registerComposerLoader($composerPath)
{
if (is_file($composerPath . 'autoload_namespaces.php')) {
$map = require $composerPath . 'autoload_namespaces.php';
foreach ($map as $namespace => $path) {
self::addPsr0($namespace, $path);
}
}
if (is_file($composerPath . 'autoload_psr4.php')) {
$map = require $composerPath . 'autoload_psr4.php';
foreach ($map as $namespace => $path) {
self::addPsr4($namespace, $path);
}
}
4.self::addPsr4
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
self::$prefixDirsPsr4[$prefix] = (array) $paths;
注:到这一步,已经将第三方类库的路径存放到Loader的静态属性$prefixDirsPsr4中,下边就是use时触发的加载第三方类库
5.think\\Loader::autoload
// 自动加载
public static function autoload($class)
{
if (isset(self::$classAlias[$class])) {
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;
}
}
6.findFile(前面第4步已经将类库的路径存放在$prefixDirsPsr4中)
private static function findFile($class)
{
if (!empty(self::$classMap[$class])) {
// 类库映射
return self::$classMap[$class];
}
// 查找 PSR-4
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
$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 . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
简单整理到这里~