PHP 自动加载总结

自动加载的测试代码

https://github.com/bayuexiong/simple-composer

1. 自动加载

php的加载文件,一般分为三种情况

  1. 直接include/require,不属于自动加载,一般用于PHP5以前的版本。
  2. 使用__autoload(),PHP5.0引入,在PHP5.1.12之后不再推荐使用。
  3. 使用spl_auoload_register(),现在使用比较多,于PHP5.1.12之后加入,提供了一种更加灵活的方式加载文件。

具体实例

第一种没什么说的。主要还是看第二种和第三种。

假设在一个项目里面有两个文件

Demo.php

class Demo
{
# coding
}

index.php

function __autoload($class_name)
{
$file = dirname(__FILE__) . '/' . $class_name;
if (file_exist($file)) {

include($file);

}

}

$obj = new Demo();

Demo.phpindex.php只要在一个同级目录内,php变会很智能的加载Demo.php,不需要显示的操作。

但是这里还是存在弊端的,比如一个项目中只能有一个__autoload(),这也意味着自动加载的价值变得很低,于是PHP便在PHP5.1.12版本之后添加了spl_autoload_register(),它接受一个回调函数,使得自动加载更加的灵活。

修改index.php

function my_autoload($class_name)

{

$file = dirname(__FILE__) . '/' . $class_name;

if (file_exist($file)) {

include($file);

}

}

spl_autoload_register('my_autoload');

$obj = new Demo();

之前的Demo.php不做修改,将index.php如此修改,便可以同样的功能。

关于spl_autoload_register()更多的内容可以查看官方文档。

http://php.net/manual/zh/function.spl-autoload-register.php

 TIPS
注意类名和文件名必须保持一致!!!

2. Composer

在5.3之后,Composer大行其道,号称PHP未来的希望。。。

使用Composer自动加载时只要引入一个自动加载文件就可以了。

include_once('vendor/autoload.php');

那么Composer的自动加载时怎么实现的呢,其实也是依靠spl_autoload_register()

首先Composer存储三对数组

class=>dir
namespace=>array(dir, dir, dir)
PSR4=>array(dir, dir1, dir2...)

然后在autoload.php, 存在一个loader,可以触发spl_autoload_register,
一旦触发,Composer会对触发的类型进行分析,选择合适的数组,将真实的地址提取出来,然后include,原理还是很简单,推荐大家自行查看一下Composer的自动加载的代码。

关于composer的一个Tips

在上线代码时可以使用composer dump-autoload -o 转换PSR-0/4 autoloadingclassmap 获得更快的载入速度。这特别适用于生产环境,但可能需要一些时间来运行,因此它目前不是默认设置。至于为什么,看完源代码就清晰了。

3. 简单实现一个Composer自动加载

简单实现ClassMap的自动加载功能

https://github.com/bayuexiong/simple-composer/tree/master/vendor

使用代码和Composer一样。

include 'vendor/autoload.php';

$obj = new Demo('gg');

$obj->sayName();

$obj2 = new Other('aa');

$obj2->sayName();

4. 如何选择自动加载机制

  1. 在程序一开始运行的时候,使用数组,将项目内所有的文件记录下来,实现自动加载(如果使用cache,应该还hold的住),symfony使用这种形式,代码如下。
    https://github.com/symfony/class-loader/blob/master/ClassMapGenerator.php
  2. class名和路径对应,便于查找,但是这样缺乏灵活性,框架的侵入性太强了,代码很受框架的限制,像ThinkPHP,CI就是使用这种形式。
  3. 组合使用,像Laravel就是使用PSR4和symfony的classLoader。

5. CI框架的自动加载

现在公司使用CI框架的情况比较多,所以对CI框架的自动加载做一些详细的介绍。

对于一个普通的CI加载类的方式:

 $this->load->library('myclass');

CI框架的内部是如何运行的呢?首先上个流程图

QQ截图20160314174227

具体的实现可以查看源代码,都在system/core/Loader.php文件下面。

其实CI框架的自动加载并没有借助spl系列的函数,而是直接查找文件的方式来自动加载,这可能与CI框架诞生的年岁有关,在那个时期不失为一种优秀的自动加载方法。

但是现在来说,算不上优秀,其对命名的规范太过苛刻了,效率也谈不上高效,当然CI框架的整体速度还是很快的,毕竟像symfony之流的框架为了实现完全解耦,付出了很多性能上的代价。

Tips

对于一个普通的加载类
$this->load->library($library, $param, $object_name);
1. $library 可以是一个数组key代表需要加载的类,value则是obejct_name。
2. $param 需要一个数组,作于传入构造器中的值
3. $object_name$this->load->model(calss, object_name)中第二个参数一样,加载完之后可以$this->object_name->sayHello()

具体的可以结合CI的文档再加上阅读CI的源代码,的确CI的文档相比其他的框架比较全面,但是一些技巧也没有详尽的介绍。

6. 小结

使用Composer吧!使用RSP4命名空间规范吧!这样各个组件与组件之间,自己的代码和别人的代码都可以无痛的结合,不需要花费额外的精力去处理文件加载的问题。

7. 补充

  1. 命名空间,命名空间提供了一种灵活的效率更高的辅助自动加载的方法。
  2. PSR4 规范命名空间的定义,是最近比较流行的命名空间规范。

材料参考:

  1. https://github.com/qinjx/adv_php_book/blob/master/class_autoload.md
  2. spl_autoload_register
  3. __atuoload

发表评论