💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] * * * * * # 1 自动加载意义 > php的自动加载实现运行时**类的自动加载**。 > php的自动加载主要实现**类名到类文件的映射** > 类名通常由**命名空间与类名组成** > 文件通常由**基于特定目录的路径表明** # 2 自动加载基础 ## 2.1 __autoload() > php5中,定义了__autoload()函数。运行时使用未被定义的类时,自动调用此函数,查找类的定义文件 ~~~ <?php function __autoload ( $class_name ) { require_once $class_name . '.php' ; } $obj = new MyClass1 (); $obj2 = new MyClass2 (); ?> ~~~ 上面例子中,会自动加载MyClass1.php和MyClass2.php文件,其中定义了对应的MyClass1和MyClass2类。 ## 2.2 spl_autoload() > spl_autoload()作为__autoload()的默认实现。默认情况下将类名转换成小写,在小写的类名后面加上.ini或.php的扩展名作为文件名,然后在所有的包含路径中查找该文件。 ## 2.3 spl_autoload_register() > spl_autoload_register注册给定的函数作为__autoload的实现。 ~~~ <?php function my_autoloader ( $class ) { include 'classes/' . $class . '.class.php' ; } spl_autoload_register ( 'my_autoloader' ); // 或者,自 PHP 5.3.0 起可以使用一个匿名函数 spl_autoload_register (function ( $class ) { include 'classes/' . $class . '.class.php' ; }); ?> ~~~ spl_autoload_register()函数是使用最为广泛的自动加载实现。 # 3 Loader类自动加载 > think5的自动加载包括Loader类和composer自动加载两种机制。 > Loader类是think5实现的自动加载类 > Loader类的自动加载包含**类的注册,加载类的缓存,类的查找,常用类的自动实例化四部分**。 > composer是通用的自动加载实现 > composer包含**namespaces,classmap,files,psr4四种加载机制**。 ## 3.1 Loader类 > Loader类在thinkphp\library\think\Loader.php文件 ## 3.2 Loader类信息缓存 ~~~ // 实例化对象缓存 protected static $instance = []; // 类名映射 protected static $map = []; // 命名空间别名 protected static $namespaceAlias = []; // PSR-4 private static $prefixLengthsPsr4 = []; private static $prefixDirsPsr4 = []; private static $fallbackDirsPsr4 = []; // PSR-0 private static $prefixesPsr0 = []; private static $fallbackDirsPsr0 = []; // 自动加载的文件 private static $autoloadFiles = []; ~~~ ## 3.3 Loader类注册 ### 1 addNamespace() `public static function addNamespace($namespace, $path = '')` > 注册命名空间到目录的映射关系 ~~~ // 注册mynamespace与library/mynamespace/目录的映射关系 // 当使用mynamespace/Myclass类时,会自动在library/mynamespace/目录下查找Myclass文件 Loader::addNamespace('mynamespace',LIB_PATH.'mynamespace'.DS); ~~~ ~~~ //注册thinknamespace的命名空间关系 $thinknamespace = [ 'think' => LIB_PATH . 'think' . DS, 'behavior' => LIB_PATH . 'behavior' . DS, 'traits' => LIB_PATH . 'traits' . DS, ]; Loader::addNamespace($thinknamespae); ~~~ ### 2 addClassMap() `public static function addClassMap($class, $map = '')` > 注册类到单个文件的映射关系 ~~~ //注册Test类与application\other\test.php文件的对应关系 //使用Test类时Loader会自动加载application\other\test.php文件 Loader::addClassMap('Test',APP_PATH.'other\test'); ~~~ ~~~ //注册MyClass1与MyClass2的与对应文件关系。 $classMap = [ 'MyClass1' => APP_PATH.'other\MyClass1', 'MyClass2' => APP_PATH.'other\MyClass2' ]; Loader::addClassMap($classMap); ~~~ ### 3 addNamespaceAlias() `public static function addNamespaceAlias($namespace, $original = '')` >注册命名空间的别名, >查找$namespace会自动查找$original命名空间 ### 4 addPsr0() `private static function addPsr0($prefix, $paths, $prepend = false)` > 注册psr0规则自动加载机制 ### 5 addPsr4() `private static function addPsr4($prefix, $paths, $prepend = false)` > 注册psr4规则自动加载机制 ## 3.4 Loader类查找 ### 1 registe() `public static function register($autoload = '')` > 注册自动加载机制 > $autoload参数为自动加载函数,默认为Loader::autoload() ### 2 registerComposerLoader() `private static function registerComposerLoader()` > 自动注册composer自动加载机制, > 在register()中检查目录VENDOR_PATH\composer\时,自动注册composer。 ### 3 autoload() `public static function autoload($class)` > 自动加载$class类 ### 4 findFile() `private static function findFile($class)` > 加载$class类对应的文件 > 主要查找三种文件映射机制, > 首先think的classmap, > 其次psr-4的文件映射, > 最后psr-0的文件映射。 ## 3.5 Loader类加载与对象实例化 ### 1 import() `public static function import($class, $baseUrl = '', $ext = EXT)` > 导入$baseUrl下的以$ext为后缀的$class的文件 > 导入的文件会缓存到$_file中 ### 2 model() `public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')` > 实例化模型对象 > 实例化后的对象缓存在Loader::$instance数组中 ### 3 controller() `public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')` > 实例化控制器对象 ### 4 validate() `public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')` > 实例化验证器对象, > 实例化后的对象缓存在Loader::$instance数组中 ### 5 db() `public static function db($config = [])` > 实例化Db对象 ### 6 action() `public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)` > 远程调用控制器方法 ## 3.6 Loader类其他功能 ### 1 parseName() `public static function parseName($name, $type = 0)` > 命名风格转换 ### 2 parseClass() `public static function parseClass($module, $layer, $name, $appendSuffix = false)` > 解析应用类的类名 ### 3 clearInstance() `public static function clearInstance()` > 清空所有实例化的对象 ### 4 __include_file() > 限制include文件的作用域 ### 5 __require_file() > 限制require文件的作用域 # 4 Composer自动加载 ## 1 Composer实现 > Composer是php的包管理机制的实现,类似node的npm,python的pypi > Composer通常用来自动下载远程网络包文件,实现框架的扩展功能 > Composer还可以用来管理框架本地的类加载。 > Composer的实现通常在框架的vendor\comoser\目录中 > 其中包含autoload_classmap.php,autoload_files.php,autoload_namespaces.php,autoload_psr4.php,autoload_real.php,ClassLoader.php等文件 > ClassLoader.php实现composer类的自动加载,其他文件包含composer的自动加载的类注册 > 每次运行composer命令时,会根据composer.json文件中的autoload规则,自动更新composer对应下的文件。 ## 2 autoload_classmap.php ~~~ ;部分代码 //定位目录 $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); //返回的类名与文件映射数组 //将类名映射到目录下的特定文件 return array( 'File_Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php', 'File_Iterator_Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php', 'File_Iterator_Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php', ....... ); ~~~ ## 3 autoload_files.php ~~~ ;部分代码 //定位目录 $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); //返回文件别名与文件路径的映射关系数组 return array( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '72c97b53391125cae04082a81029f42d' => $vendorDir . '/topthink/think-testing/src/config.php', '9e05116ddaa5b1d244b68c3993908acd' => $vendorDir . '/topthink/think-queue/src/config.php', 'ddc3cd2a04224f9638c5d0de6a69c7e3' => $vendorDir . '/topthink/think-migration/src/config.php', '1cfd2761b63b0a29ed23657ea394cb2d' => $vendorDir . '/topthink/think-captcha/src/helper.php', ); ~~~ ## 4 autoload_namespaces.php ~~~ //定位目录 $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); //返回命名空间到目录的映射数组 return array( 'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'), ); ~~~ ## 5 autoload_psr4.php ~~~ //定位目录 $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); //返回psr4规则映射 return array( 'think\\testing\\' => array($vendorDir . '/topthink/think-testing/src'), 'think\\sae\\' => array($vendorDir . '/topthink/think-sae/src'), 'think\\queue\\' => array($vendorDir . '/topthink/think-queue/src'), ); ~~~ ## 6 autoload_real.php > composer的自动加载实现 ## 7 ClassLoader.php > composer的自动加载类 # 5 自动加载应用 ## 1 thinkphp\base.php ~~~ // 载入Loader类 require CORE_PATH . 'Loader.php'; // 注册自动加载 \think\Loader::register(); ~~~ ## 2 thinkphp\library\App.php ~~~ // App::run() // 清空类的实例化 Loader::clearInstance(); // App::initCommon() // 注册配置的命名空间映射 self::$namespace = $config['app_namespace']; Loader::addNamespace($config['app_namespace'], APP_PATH); if (!empty($config['root_namespace'])) { Loader::addNamespace($config['root_namespace']); } //App::init() // 加载应用或模块别名配置文件 if (is_file(CONF_PATH . $module . 'alias' . EXT)) { Loader::addClassMap(include CONF_PATH . $module . 'alias' . EXT); } ~~~ ## 3 Class查找异常 > 通常Class查找失败,框架会抛出异常 ~~~ //Class查找失败代码 PHP Fatal error:Class 'Think\Log' not found ~~~ > 解决办法 ~~~ 1 确定引入命名空间或者使用绝对命名空间 use think; \think\Log::init() 2 引入命名空间依然失败,查找命名空间对应目录的文件 ~~~ # 6 其他资料 [php的自动加载](http://www.kancloud.cn/zmwtp/tp5/119447) [composer的使用](http://www.kancloud.cn/zmwtp/tp5/120009) [Loader的分析](http://www.kancloud.cn/zmwtp/tp5/127348) [Loader的对象实例化](http://www.kancloud.cn/zmwtp/tp5/120008)