自动加载Loader类
一.概述
系统会调用Loader::register()方法注册自动加载,在这一步完成后,所有符合规范的类库(包括Composer依赖加载的第三方类库)都将自动加载。
系统的自动加载由两个部分组成:
1.注册系统的自动加载方法 \think\Loader::autoload
2.注册Composer自动加载(符合Composer规范即可)
一个类库的自动加载检测顺序为:
1.是否定义类库映射;
2.Composer自动加载检测;
3.是否为注册的命名空间;
4.检测EXTEND_PATH目录下的扩展类库;
如果检测到以上任何一处,则按照PSR-4命名规范自动加载。
可以看到,定义类库映射的方式是最高效的。
二.autoload类
在Loader::autoload($class); 中打印出$class,运行如下:
可见$class为带命名空间的类名。
检测命名空间别名:有没有自动加载?
比如定义了一个类 kukiiu/Upload。给他定义一个命名空间别名org,这样我使用org/Upload类,就会用kukiiu/Upload类重新定义一个org/Upload类。
定义命名空间别名方法:
1.\think\Loader::addNamespaceAlias(‘org‘,‘kukiiu‘);
检查是否定义类库映射
打印出$map可看到里面的每项元素如下所示:
["think\App"]=> string(45) "F:\hwphp\study\thinkphp\library\think\App.php"
定义了映射后,在直接使用该类时就会去搜索定义给出的文件路径名,然后加载该文件。
在mode/common.php中定义了很多常用的类映射。
定义映射方法:
1.\think\Loader::addMap(‘test‘,APP_PATH.‘index\controller\Test.php‘);
dump(class_exists(‘test‘));
2.mode/common.php的alias是不是添加到map中?
Composer自动加载
执行composer install后,会在thinkphp/vendor下创建依赖文件。
1.tp在初始化时解析vendor/composer下的自动加载机制Loader::registerComposerLoader()。
a) 加载PSR-0规范的‘composer/autoload_namespaces.php’文件。
解析后得到 self::$prefixesPsr0为:
b) 加载PSR-4规范的‘composer/autoload_psr4.php‘文件。
解析后得到 $prefixLengthsPsr4为:
$prefixDirsPsr4为:
c) 加载类映射文件(跟tp的类映射相同):‘composer/autoload_classmap.php‘。
d) 直接加载类文件。。。‘composer/autoload_files.php‘
2.在查找类时使用Loader::findFileInComposer()查看是否是composer下的类。
有点复杂,以后再看!
命名空间自动加载
没设置类映射,基本都是通过这里加载的类。打印出进入命名空间自动加载的类看看:
// 解析命名空间
list($name, $class) = explode(‘\\‘, $class, 2);
将$class的第一个\前的值取出来:
如”app\index\controller\Index” 得到 $name=’app’ $class=’index\controller\Index’
if (isset(self::$namespace[$name])) {
// 注册的命名空间
$path = self::$namespace[$name];
} elseif (is_dir(EXTEND_PATH . $name)) {
// 扩展类库命名空间
$path = EXTEND_PATH . $name . DS;
} else {
return false;
}
$filename = $path . str_replace(‘\\‘, DS, $class) . EXT;
1.注册命名空间:
判断$name值在不在注册的$namespace中,这里的命名空间和概念命名空间不是同一个意思,容易搞混,这里注册的$namespace是一个标识,感觉叫命名空间前缀会好点,按PSR-0规范应该叫‘供应商vendor’,看mode/common.php可以看到,默认的一些$namespace定义:
Loader::auotload()中打印出来$namespace如下所示:
所以$namespace作用就是:将命名空间的第一个\前的值$class作为前缀,通过这个前缀找到它代表的路径。如app标识就代表了”F:\hwphp\study\application\”这个路径,之后如果在使用这个路径下的某个类,如
命名空间为\app\myclass\Test的类,就会将前缀替换为F:\hwphp\study\application\myclass\Test.php,从而加载该类文件。
例如:在tp框架里,每个模块都放在application下,而$namespace里有个’app’代表了这个路径,所以模块中的类只要命名空间符合tp规定的规范,就能够通过命名空间转为文件路径,如\app\index\controller\Index控制器,就能转换为”F:\hwphp\study\application\index\controller\Index.php”文件路径。
tp的命名空间自动加载类是基于PSR-4标准,定义的$namespace的key是命名空间前缀,value是类的基路径。在得到类的全名后:将命名空间前缀替换为基路径,将其余命名空间添加到其后,添加类名和后缀。和PSR-4不同的是,这里的命名空间前缀只有一层,免去了循环判断前缀的操作,(list($name,
$class) = explode(‘\\‘, $class, 2);)。简易流程如下所示:
手动注册命名空间(标志)方法:
1.在应用入口文件中添加下面的代码:
\think\Loader::addNamespace(‘kukiiu‘,‘../extend/kukiiu/‘);
\think\Loader::addNamespace([
‘kukiiu‘=> ‘../extend/‘kukiiu‘/‘,
‘org‘ => ‘../extend/org/‘,
]);
2.在应用的配置文件中添加配置,系统会在应用执行的时候自动注册。
‘root_namespace‘ => [
‘my‘ => ‘../application/extend/my/‘,
]
3.在mode/common.php下$namespace下增加。
2.扩展类库命名空间:
thinkphp实现了自动注册命名空间(标识)机制,
把自己的类库包目录放入EXTEND_PATH目录(thinkphp/extend,可配置),就可以自动注册对应的命名空间(标识),
例如:在thinkphp/extend目录下面新增一个mylib目录,然后定义一个\mylib\Test类( 类文件位于thinkphp/extend/mylib/Test.php),就可以直接调用new \mylib\Test();
在入口文件定义常量EXTEND_PATH,可以自定义扩展类库目录。
可以看出,tp的扩展类是基于PSR-0的自动加载标准。
其他函数:
...
参考资料:
1.http://www.php-fig.org/psr。PSR标准官网。