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引入的操作