CI框架源码阅读笔记9 CI的自动加载机制autoload
本篇并不是对某一组件的详细源码分析,而只是简单的跟踪了下CI的autoload的基本流程。因此,可以看做是Loader组件的分析前篇。
CI框架中,允许你配置autoload数组,这样,在你的应用程序初始化时,会自动加载相应的类库,例如,在application/config/autoload.php中,autoload的配置如下:
$autoload['libraries'] = array("smarty", "redis");
则CI框架初始化时,会自动加载libraries下面的smarty.php和redis.php,并且在你的应用程序控制器中,可以通过$this->smarty->xxx 和$this->redis->yyy的方式调用你的类库。
CI允许autoload中配置的自动加载的类别有:
1.Packages ---包 2.Libraries --类库 3.Helper files ---用户自定义的辅助文件 4.Custom config files ---用户自定义配置文件 5.Language files ---语言包 6.Models ---模型类
我们接下来以Libraries的自动加载为例,在追踪CI的autoload之路。
由于Loader是CI中组件加载的管理器,而Loader是在CI_Controller中被加载的,因此我们从Controller加载Loader组件开始追踪。
1. CI_Controller
在CI_Controller中追踪到这样一句话:
1 2 | $this ->load =& load_class( 'Loader' , 'core' ); $this ->load->initialize(); |
于是我们猜想,在Loader的initialize的过程中,对autoload做了相应的处理。
2. Loader的initialize方法实现
1 2 3 4 5 6 7 8 9 10 | public function initialize() { $this ->_ci_classes = array (); $this ->_ci_loaded_files = array (); $this ->_ci_models = array (); $this ->_base_classes =& is_loaded(); $this ->_ci_autoloader(); //注意这里,看方法的名字,也可以猜到是对autoload的处理 return $this ; } |
Initialize的前面四个语句,用于对本身的属性、参数等初始化,不是我们需要关心的内容,真正执行autoload的应该是$this->_ci_autoloader(),沿着该线索,我们进入_ci_autoload的内部:
3. _ci_autoloader的方法:
(1).首先引入autoload的配置数组:
1 2 3 4 5 6 7 8 | if (defined( 'ENVIRONMENT' ) AND file_exists (APPPATH. 'config/' .ENVIRONMENT. '/autoload.php' )) { include (APPPATH. 'config/' .ENVIRONMENT. '/autoload.php' ); } else { include (APPPATH. 'config/autoload.php' ); } |
(2). 由于我们这次只追踪libraries的autoload机制,因此我们略过对packages和config等的autoload处理机制,而直接寻找对libraries的处理:
1 2 3 4 5 6 7 8 | if (isset( $autoload [ 'libraries' ]) AND count ( $autoload [ 'libraries' ]) > 0) { //ignore database eg. foreach ( $autoload [ 'libraries' ] as $item ) { $this ->library( $item ); } } |
可以看出,对所有的autoload的libraries,实际上是执行了library方法,再次进入library方法查看。
4. library方法实现。
上述对该方法的调用中,传递的是autoload中配置的类库名(我们的例子是redis和smarty),library方法的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public function library( $library = '' , $params = NULL, $object_name = NULL) { if ( is_array ( $library )) { foreach ( $library as $class ) { $this ->library( $class , $params ); } return ; } if ( $library == '' OR isset( $this ->_base_classes[ $library ])) { return FALSE; } if ( ! is_null ( $params ) && ! is_array ( $params )) { $params = NULL; } $this ->_ci_load_class( $library , $params , $object_name ); } |
可以看出,如果$library是数组,则会循环调用library方法。实际上最终会调用$this->_ci_load_class。再次进入_ci_load_class查看.
5. _ci_load_class的实现
撇开其中的错误检查和安全检查,我们只看关键的代码:
1 | return $this ->_ci_init_class( $class , config_item( 'subclass_prefix' ), $params , $object_name ); |
该方法,将对类库的初始化抛给了_ci_init_class处理:
1 2 3 4 5 6 7 8 9 | $CI =& get_instance(); //获取Controller的实例 if ( $config !== NULL) { $CI -> $classvar = new $name ( $config ); } else { $CI -> $classvar = new $name ; } |
到这里,我们总算了解了CI的autoload的基本流程(漫漫长征),作为对Loader组件的初步追踪,我们省略了中的许多实现细节,这些我们将在对Loader组件的分析过程中慢慢添加上。
总结一下autoload的基本流程:
1. Application/config/autoload.php中配置需要autoload的类库 2. Controller实例化的时候,会加载Loader组件,并调用该组件的initialize方法,对需要的资源初始化. 3. 经过更多的错误检查和安全性检查的步骤,加载需要的类库、配置等。
最后说一句,并不是所有的类库都需要通过CI的autoload加载,因为该类库在框架初始化的时候就被加载,而不管你是不是需要使用该类库,这样实际上会有一定的性能损失。如果你的类库并不是所有应用都需要的,那么,更好的方法是需要时再加载。关于这一点,我们之后在分析Loader组件的设计和实现时会进一步详细说明。
本篇的参考文献:
1. http://itopic.org/codeigniter-config-autoload.html
2. http://codeigniter.org.cn/user_guide/general/autoloader.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?