上一节简单实现了 CI 的类库扩展模型,所以 _ci_load_class 和 _ci_init_class 写的不是很完备。根据上节课的分析,当 system/libraries 目录下存在 Email.php, 然后在 application/libraies 目录下存在 My_Email.php 时就可以实现扩展类库的功能。除了扩展之外,我们还需要:

1)直接覆盖原始类

2)完全自定义类

很简单,按照约定,当不存在MY_开头的类库文件,加载类库的情况必定属于以上两种,如下所示

// 直接加载代码
$is_duplicate = FALSE;
foreach ($this->_ci_library_paths as $path) {
$filepath = $path.'libraries/'.$subdir.$class.'.php'; if ( ! file_exists($filepath)) {
continue;
} if (in_array($filepath, $this->_ci_loaded_files)) { if ( ! is_null($object_name)) {
$CI =& get_instance();
if ( ! isset($CI->$object_name)) {
return $this->_ci_init_class($class, '', $params, $object_name);
}
} $is_duplicate = TRUE;
log_message('debug', $class." class already loaded. Second attempt ignored.");
return;
} include_once($filepath);
$this->_ci_loaded_files[] = $filepath;
return $this->_ci_init_class($class, '', $params, $object_name);
}

其中 _ci_libraries_path 在初始构造函数中初始化如下:

$this->_ci_library_paths = array(APPPATH, BASEPATH);

注意顺序,先是 APPPATH, 然后再是 BASEPATH, 保证加载的顺序先是 application ,再是 system。

再来看一下 _ci_init_class 函数

public function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) {

        if ($prefix == '') {
if (class_exists('CI_'.$class)) {
$name = 'CI_'.$class;
} elseif (class_exists(config_item('subclass_prefix').$class)) {
$name = config_item('subclass_prefix');
} else {
$name = $class;
}
} else {
$name = $prefix.$class;
} if ( ! class_exists($name)) {
log_message('error', "Non-existent class: ".$name);
show_error("Non-existent class: ".$class);
} $class = strtolower($class); // 这里对名字做了一个特殊的映射,针对 unit_test 就可以直接用 unit, 而非 unit_test
if (is_null($object_name)) {
$classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];
} else {
$classvar = $object_name;
} // 保存 class 名和对象名, 以供判断某个类库是否加载
$this->_ci_classes[$class] = $classvar; $CI =& get_instance();
if ($config !== NULL) {
$CI->$classvar = new $name($config);
} else {
$CI->$classvar = new $name;
}

分析以上代码可以发现,为了直接覆盖原始的类库文件,对 $prefix ==‘’ 的情况作了进一步处理,判断是否存在 CI 或自定义MY_前缀的类,从而保证获得正确的类名。

实例名也考虑到了一种特殊的情况,比如加载 unit_test 类的时候,直接使用 unit 作为变量,这也值得我们借鉴和考虑!!!也就是说,在考虑到一般的情况下,还可以做更灵活的处理,对类名较长的类直接通过配置的方式指定实例名,非常简洁~

总结: 整个过程加载类库的设计就完成了,特别灵活和方便。

一步一步重写 CodeIgniter 框架 (10) —— 使用 CodeIgniter 类库(续)的更多相关文章

  1. 一步一步重写 CodeIgniter 框架 (9) —— 使用 CodeIgniter 类库

    通过前面几节的内容,我们从零开始搭建了一个非常方便的MVC框架,理解了 CodeIgniter 框架最核心的部分.然而一个框架的便利不仅仅在于提供一个MVC就可以了,它还必须具有较高的扩展性.下面将从 ...

  2. 一步一步重写 CodeIgniter 框架 (11) —— 使用 CodeIgniter 函数库

    在完成了CI框架的类库扩展后,很自然我们就会想到函数库的扩展.函数库的扩展在 CI 中称为 helper 函数与类有不同的地方,它不能继承,只能覆盖或者添加新的函数,或者直接完全新定义的一组函数. 由 ...

  3. **【ci框架】精通CodeIgniter框架

    http://blog.csdn.net/yanhui_wei/article/details/25803945 一.大纲 1.codeigniter框架的授课内容安排 2.codeigniter框架 ...

  4. CodeIgniter框架——知识要点汇总

    NO1.学习要点: 一.CodeIgniter 框架的简介 二.CodeIgniter 框架的安装 三.CodeIgniter 框架的目录结构分析 四.CodeIgniter 框架是如何工作的? 五. ...

  5. 一步一步重写 CodeIgniter 框架 (6) —— 实现在控制器Controller中加载View

    1. 控制器将模型类获得的数据,传递给视图进行显示,所以视图必须负责接收数据,另外重要的一点是当模型和视图分开后,多个模型的数据可以传递给一个视图进行展示,也可以说一个模型的数据在多个不同的视图中进行 ...

  6. 一步一步重写 CodeIgniter 框架 (5) —— 实现Controller,并加载Model

    CodeIgniter 框架采用MVC模式,而MVC模式中起纽带作用的就是C(控制器),在控制器的中通过加载模型获得数据,将数据传到视图中进行展示.本课将实现在控制器中加载模型. 1. 控制器的实现 ...

  7. 一步一步重写 CodeIgniter 框架 (4) —— load_class 管理多个对象实例的思路

    我们使用CodeIgniter 框架最主要是想利用其 MVC 特性,将模型.视图分开,并通过控制器进行统一控制.在尝试实现 MVC 模式之前,我们将实现其中一个对程序结构非常有用的技巧,就是 load ...

  8. 一步一步重写 CodeIgniter 框架 (3) —— 用面向对象重构代码

    前面两篇文章为了重点突出 CodeIgniter 框架的原理,程序的结构很乱,有很多全局变量,在这一课中我们采用面向对象的方法对原先代码进行重构. 到目前为止,程序主要完成的就是 URL 分析,并根据 ...

  9. 一步一步重写 CodeIgniter 框架 (1) —— url 如何映射到具体的方法

    CodeIgniter 框架最显著的特征就是 MVC 模式,它的做法就是提取 url 中的'分段', 映射到某个类的某个方法,从而由该方法来输出最终显示的页面内容.那么我们第一课中就是实现一个这样的原 ...

随机推荐

  1. Mac 让 iTerm2 记住用户名密码 expect 脚本

    刚刚用iTerm2的时候,总是要一遍遍的敲用户名.密码. 我在想, 能不能像Windows的软件一样,可以直接让软件记住.然后只要点击一下,就直接ssh到远程服务器上面去了. 之后经过搜索,可以用ex ...

  2. 可以放在html代码中的自动跳转代码

    可以放在html代码中的自动跳转代码 有3种方法可以实现html的页面跳转,1,refresh   2,onload事件中加入代码  3,js实现 1.<html><body> ...

  3. 开源流媒体处理库live555服务器端、客户端源代码分析总结

    RTSP服务器端流程: 1. RTSP连接的建立过程 RTSPServer类用于构建一个RTSP服务器,该类同时在其内部定义了一个RTSPClientSession类,用于处理单独的客户会话. 首先创 ...

  4. HDOJ 1226 超级密码(bfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1226 思路分析:题目要求寻找一串长度不大于500的C进制的密码,且该密码需要为十进制数N的整数倍. & ...

  5. js动态加载控件jsp页面

    例子1:(具体参照drp中的flow_card_add.jsp)<script>    var rowIndex = 0;     function addOneLineOnClick() ...

  6. Scraping JavaScript webpages with webkit | WebScraping.com

    Scraping JavaScript webpages with webkit | WebScraping.com Scraping JavaScript webpages with webkit ...

  7. JAVA 创建TXT文件,写入文件内容,读取文件内容

    [java]  view plain copy   package com.abin.facade.ws.mail.function; import java.io.BufferedReader; i ...

  8. GDI+入门——带你走进Windows图形的世界

    一.GDI+基础 1.GDI+简单介绍 GDI+是微软的新一代二维图形系统,它全然面向对象,要在Windows窗口中显示字体或绘制图形必需要使用GDI+.GDI+提供了多种画笔.画刷.图像等图形对象, ...

  9. DontDestroyOnLoad(Unity3D开发之五)

    Unity中我们从A场景切换到B场景的时候,A场景全部对象都会销毁,但有时候我不须要销毁某些东西. 比方一个简单的游戏的背景音乐,我不须要多次反复创建,多个场景播放这一个即可了.这个时候就须要用到Do ...

  10. 1.自己写一个计算器demo

    知识点: 1.System.Math.Pow() 实现乘方 2.实现计算器的运算优先级,依次调用的流程 问题: 还未实现“()”功能 解决方案 UI: