在TP5的框架使用过程中,自动加载类是可能会接触到,上手不难,但若想随心所欲的用,还是需要了解一番。用了千次,却没看过一次源码,学习源码,起码对TP5这个框架使用更加得心应手,毕竟技术服务于业务,能够写出更简介、更方便、更有效的业务代码,本身就是一件身心愉悦的事儿;
自动加载流程
第一步,TP框架初始化
Loader会走如下逻辑;
加载autoload_static.php中的 prefixLengthsPsr4和prefixDirsPsr4两个数组;
public static $prefixLengthsPsr4 = array ( 't' => array ( 'think\\composer\\' => 15, 'think\\' => 6, ), 'a' => array ( 'app\\' => 4, ), ); public static $prefixDirsPsr4 = array ( 'think\\composer\\' => array ( 0 => __DIR__ . '/..' . '/topthink/think-installer/src', ), 'think\\' => array ( 0 => __DIR__ . '/../..' . '/thinkphp/library/think', ), 'app\\' => array ( 0 => __DIR__ . '/../..' . '/application', ), );
再通过self::${$attr} = $composerClass::${$attr}
变成当前类的静态数组;
详细逻辑如下:
// Composer 自动加载支持 if (is_dir(VENDOR_PATH . 'composer')) { if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . 'composer' . DS . 'autoload_static.php')) { //引入'autoload_static.php; require VENDOR_PATH . 'composer' . DS . 'autoload_static.php'; //获取全部对象 $declaredClass = get_declared_classes(); //弹出最后一个对象类 也就是autoload_static.php $composerClass = array_pop($declaredClass); //查看autoload_static.php对象数组 foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { //转化成自己类的静态数组 self::${$attr} = $composerClass::${$attr}; } } } else { //加载Psr0方法 self::registerComposerLoader(); } } // 注册命名空间定义 self::addNamespace([ 'think' => LIB_PATH . 'think' . DS, 'behavior' => LIB_PATH . 'behavior' . DS, 'traits' => LIB_PATH . 'traits' . DS ]); // 加载类库映射文件 if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); } self::loadComposerAutoloadFiles(); // 自动加载 extend 目录,可以在这里加相关目录,拓展包就是在这手动放入 extend中加载 self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
第二步 new class()
当一个class不存在走自动加载方法; spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true)
通过spl_autoload_register 走autoload($class)方法;
autoload($class)->检测命名空间别名->通过上一步初始化生成的静态化数组查找相关class文件是否存在->返回对像(结束);
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; }
其中核心方法
public static function register($autoload = null) { // 注册系统自动加载 spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); }
TP自动加载方法
composer自动方法
其实两个自动加载打通小异;
Tp在加载方法,个人认为是借鉴composer;