ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
[TOC] * * * * * ## 1 加载器接口 ### 加载器初始化 >[info] 注册加载器函数 `public static function register($autoload = '')` > $autoload: 加载器函数 默认为Loader::autoload() * * * * * ### 注册命名空间/类名别名 >[info] 注册命名空间别名 `public static function addNamespace($namespace, $path = '')` > $namespace:待注册命名空间 > $path:待注册命名空间对应目录 * * * * * >[info] 注册类名别名 `public static function addMap($class, $map = '')` > $class:待注册类名 > $map:待注册类名对应别名 * * * * * ### 加载文件 >[info] 类Java加载函数 `public static function import($class, $baseUrl = '', $ext = EXT) ` > $class:加载的类名 > $baseUrl:加载的类文件目录 > $ext:加载的文件后缀 * * * * * >[info] 类自动加载 `public static function autoload($class) ` > $class:加载的类名 ## 2 加载器原理 ### 加载器初始化 Loader::rigister() `spl_autoload_register($autoload ? $autoload : 'think\\Loader::autoload');` 注册系统自动加载$autolaod `self::registerComposerLoader();` 注册composer自动加载 * * * * * >[info] composer自动加载注册 Loader::registerComposerLoader() composer自动加载原理见 [php的自动加载](http://www.kancloud.cn/zmwtp/tp5/119447#4-composer-) `if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {}` composer/autoload_namespaces.php注册到self::$prefixesPsr0 `if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) {}` composer/autoload_psr4.php注册到self::$prefixDirsPsr4[$namespace] `if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) {}` composer/autoload_classmap.php注册到self::$map `if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {}` composer/autoload_files.php中文件依次加载 ### 命名空间与目录关系注册 Loader::addNamespace() `self::$namespace = array_merge(self::$namespace, $namespace);` $namespae为 array('namespace1'=>'path1','namespace2'=>'path2'), $path为空时,将$namespace合并到self::$namespace。 `self::$namespace[$namespace] = $path;` 两个参数则注册$namespace与$path到self::$namespace ### 类名与文件关系注册 Loader::addMap() `self::$map = array_merge(self::$map, $class);` $class为array('class1'=>'map1','class2'=>'map2') $map为空时,将$class合并到self::$map。 `self::$map[$class] = $map;` 两个参数注册$class与$map关联到self::$map ### 文件自动加载 Loader::autoload() `if (isset(self::$map[$class])) {}` 首先检查类别名对应的类文件, 如果存在,则加载对应类文件 `elseif ($file = self::findFileInComposer($class)) {}` 次之使用Composer加载对应类文件 `else {}` 最后解析类名中的命名空间,类到对应文件,并加载 ### 文件手动加载 Loader::import() `static $_file = [];` 手动加载文件的全局缓存数组 $class参数解析: `$class = str_replace(['.', '#'], [DS, '.'], $class);` 将$class参数中的符号"." "#"解析为目录分隔符, ~~~ if (isset($_file[$class . $baseUrl])) { return true; } else { $_file[$class . $baseUrl] = true; } ~~~ 检查$_file全局缓存数组是否已加载。 $baseUrl参数解析: `if (empty($baseUrl)) {}else{}` 检查是否添加$baseUrl参数。 `list($name, $class) = explode(DS, $class, 2);` 将$class以目录分割符分解为到目录名$name,文件名$class变量中 ~~~ if (isset(self::$namespace[$name])) { $baseUrl = self::$namespace[$name]; } ~~~ $name对应的目录已注册到$namespace,获取对应目录。 ~~~ elseif ('@' == $name || MODULE_NAME == $name) { $baseUrl = MODULE_PATH; } ~~~ $name为@或者MODULE_NAME,获取对应模块目录。 `elseif (in_array($name, ['traits', 'think', 'behavior']))` $name为traits,think,behavior等根命名空间,获取对应目录 `elseif (APP_NAMESPACE == $name) ` $name为应用命名空间,获取应用目录 `elseif (is_dir(EXTEND_PATH . $name))` $name为框架扩展目录,获取扩展目录 ~~~ else { $baseUrl = APP_PATH . $name . DS; } ~~~ $name为应用的$name的目录 ~~~ elseif (substr($baseUrl, -1) != DS) { $baseUrl .= DS; } ~~~ $baseUrl参数存在,则解析为$baserUlr目录 `$filename = $baseUrl . $class . $ext;` 根据$baseUrl,$class,$ext合成目标文件名 ~~~ if (is_file($filename)) { if (APP_DEBUG && IS_WIN && false === strpos(realpath($filename), $class . $ext)) { return false; } include $filename; return true; } ~~~ 对应目标文件存在,加载对应目标文件。 ## 3 加载器框架示例 ~~~ thinkphp\start.php Loader::register(); if (isset($mode['namespace'])) { Loader::addNamespace($mode['namespace']); } if (isset($mode['alias'])) { Loader::addMap(is_array($mode['alias']) ? $mode['alias'] : include $mode['alias']); } ~~~ ~~~ thinkphp\library\think\App::run() if (!empty($config['root_namespace'])) { Loader::addNamespace($config['root_namespace']); } ~~~ ~~~ thinkphp\library\think\App::initModule() if (is_file($path . 'alias' . EXT)) { Loader::addMap(include $path . 'alias' . EXT); } ~~~