1.基本知识
1. include, require
2.如何实现类的自动加载 spl_autoload_register() __autoload() 3.自动加载规范1.PSR-0:https://github.com/PizzaLiu/P...
2.PSR-4:https://github.com/PizzaLiu/P...
2.Yii2中代码自动加载的机制
在Yii2.0的运行过程中主要由以下两个方法来实现代码的自动加载:
1.path_to_your_project/vendor/composer/ClassLoader.php中的ClassLoader::loadClass()方法,这个方法是由composer提供的。
2.类yiiBaseYii的autoload()方法,这个方法是由Yii2框架提供的
Yii2中是如何实现代码的自动加载的?
入口脚本两行代码:
require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
3.关于autoload.php:
1.注册ComposerAutoloaderInit06ca19902d5e5679bb4a73b919aadb2a::loadClassLoader($class)为自动加载函数。这个loader负责引入了一个类:ClassLoader.php中的ComposerAutoloadClassLoader(),随后立即解除注册。
2.注册vendor/composer/ClassLoader.php中的ClassLoader::loadClass($class)为自动加载函数,并利用配置文件(即vendor/composer目录下的autoload_*.php文件)对这个自动加载函数进行了初始化。这个函数实现了PSR-0,PSR-4,classmap等方式来自动加载。
3.Require “vendor/composer/autoload_static.php”中的$files(作为全局函数使用) ??
autoload_*.php的解释:
1. autoload_static 主要是为了提高效率,相当于缓存
当满足以下条件:
1.PHP_VERSION_ID >= 50600
2.&& !defined('HHVM_VERSION')
3.&& (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
则直接使用autoload_static文件而不采用上面的4个文件。
2.autoload_namespaces.php 对应的是一些符合PSR-0的目录或文件
3. autoload_psr4.php 包含的命名空间目录:vendor/yiisoft下满足psr-4的目录(包括yii命名空间,即yii api 中包含的类)
4.autoload_classmap.php
命令"composer dump-autoload -o"会生成这么一个文件,通过classmap方式,可以提高自动加载的效率
(相比使用PSR-0或PSR-4自动加载,可以减少计算量和IO
5.autoload_files.php 主要包括了需要立即require的文件( 通常是库文件,也可以是自定义的,引入作为全局函数使用)
上面关于Closure::bind()的使用参考http://www.cnblogs.com/iforev...
使用ComposerAutoloadClassLoader::loadClass()加载文件的顺序:
- 1.先从classMap中找(时间复杂度O(1))
- 2.查看是否文件之前已经查找过,证实不存在($missingClasses)
- 3.如果有使用apc缓存的话从缓存中取
-
4.查找文件名后缀为”.php”的文件
- a)PSR-4 lookup:格式化类名,通过prefixLengthsPsr4,prefixDirsPsr4找到文件的绝对路径 - b)PSR-4 fallback:根据$fallbackDirsPsr4查找根命名空间下的目录 - c)PSR-0 lookup:分纯pear格式,pear+命名空间格式,根据prefixesPsr0找到文件的绝对路径 - d)PSR-0 lookup:根据fallbackDirsPsr0查找根命名空间下的目录 - e)PSR-0 include:如果允许使用include path方式的话,使用stream_resolve_include_path()返回绝对路径 - f)找不到,返回false
- 5.如果有使用HHVM的话,找后缀为”.hh”的文件,回到4下的具体查找(即a,b,c..)
- 6.如果有使用apc缓存的话,将找到的文件的绝对路径存储到apc缓存中
注意:
1.在ClassLoader::findFileWithExtension($class, $ext)中实现了PSR-0和PSR-4的自动加载,其时间复杂度均为O(n2),相比于classmap的方式而言(时间复杂度为O(1))是低效的,因此在生产环境中可以采用composer命令"composer dump-autoload -o"进行优化
4.其中Yii.php 的作用:
1.定义类Yii(需要手动引入其父类的文件,而不是靠自动加载)
2.注册Yii::autoload()为自动加载函数
3.赋值Yii::$classMap (其值即yii2 api 中介绍的所有类,对应文件vendoryiisoftyii2classes.php)
4.生成依赖注入容器:Yii::$container = new yiidiContainer();
相对于ComposerAutoloadClassLoader::loadClass(),Yii.php所做的就简单明了许多了,如果所需加载的类在Yii::$classMap中有定义则直接通过它加载,没有的话就解析别名,然后加载。如果解析别名后依然找不到相应的文件路径,则使用composer提供的自动加载函数来加载(即ClassLoader::loadClass($class))
Yii::autoload()主要能引入什么类?
1.Yii::$classMap中定义的yii2核心类
2.引入我们的应用中自己创建的类(依靠命名空间和别名,遵循PSR-4)
最终注册了的自动加载方法以及顺序:
1.Yii::autoload()
2.vendorcomposerClassLoader.php中的ClassLoader::loadClass($class)
.自动加载器YiiBase::autoload()
- a)先从静态变量$classMap中找(从代码中看,这个貌似貌似没有用到)
- b)再从静态变量$_coreClasses中找 (这个写死在YiiBase文件中了,包含了所有api)
- c)如果允许 include_path,则直接include
- d)不允许 include_path,根据self::$_includePaths 逐一查找文件,找到的话就include
- e)按照类psr-4的方式查找( 与 .)(注意:这里这里需要用到一些常见的别名)
-
/** * Class autoload loader. * This method is provided to be invoked within an __autoload() magic method. * @param string $className class name * @return boolean whether the class has been loaded successfully */ public static function autoload($className) { // use include so that the error PHP file may appear if(isset(self::$classMap[$className])) include(self::$classMap[$className]); elseif(isset(self::$_coreClasses[$className]))//这个数组是写死在YiiBase中的,包含所有yii api include(YII_PATH.self::$_coreClasses[$className]); else { // include class file relying on include_path if(strpos($className,'\')===false) // class without namespace { if(self::$enableIncludePath===false) { foreach(self::$_includePaths as $path) { $classFile=$path.DIRECTORY_SEPARATOR.$className.'.php'; if(is_file($classFile)) { include($classFile); if(YII_DEBUG && basename(realpath($classFile))!==$className.'.php') throw new CException(Yii::t('yii','Class name "{class}" does not match class file "{file}".', array( '{class}'=>$className, '{file}'=>$classFile, ))); break; } } } else include($className.'.php'); } else // class name with namespace in PHP 5.3 { $namespace=str_replace('\','.',ltrim($className,'\')); if(($path=self::getPathOfAlias($namespace))!==false) include($path.'.php'); else return false; } return class_exists($className,false) || interface_exists($className,false); } return true; }