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

1. 控制器的实现

CodeIgniter 中控制器的作用很强大,通过继承CI_Controller 类就可以 $this->input 获得Input类的实例,其模型的调用方法是 $this->load->model('model'), 之后就可以通过 $this->model_name->调用相应模型的方法获取数据了。

那么如何实现的呢?请看 CodeIgniter 中 CI_Controller 的源码。

 class CI_Controller {

     private static $instance;

     /**
* Constructor
*/
public function __construct()
{
self::$instance =& $this; // Assign all the class objects that were instantiated by the
// bootstrap file (CodeIgniter.php) to local class variables
// so that CI can run as one big super object.
foreach (is_loaded() as $var => $class)
{
$this->$var =& load_class($class);
} $this->load =& load_class('Loader', 'core'); $this->load->initialize(); log_message('debug', "Controller Class Initialized");
} public static function &get_instance()
{
return self::$instance;
}
}

它定义了一个静态成员变量,并在初始化时等于自己 self::$instance =& $this; 然后就可以通过 get_instance 静态函数获得该实例。

foreach 循环将 通过 load_class 函数管理的实例对象(非常重要的对象,如Input,Output等)赋值作为该类的成员变量,也就是说 $this->input 相当于 load_class('Input‘)。所有控制器类通过继承 Controller 基类,就可以同样获得这种便利!!

值得注意的是,与其他核心类不同, Loader  类是在这里的构造函数处进行的,说明了 Loader  类对于 Controller 的重要性。

$this->load =& load_class('Loader', 'core');

2. Loader 类的 model 实现

Loader 类管理的 model 会比较多,上节课着重讲了 load_class 这种管理多个实例的原理,以下 model 函数就不难理解。

按照 CodeIgniter 的管理,一般会定义几个搜索路径,所以可以在 Loader 中定义两个变量

    protected $_ci_model_paths = array();

    protected $_ci_models = array();

其中 $_ci_model_paths 代表路径, $_ci_models 代表已加载的模型。

在构造函数中,将$_ci_model_paths 初始化为 APPPATH,由于在本课中还没有分层,APPPATH 等同于当前目录,让 $_ci_model_paths = array('');

然后定义 model 函数

public function model($model, $name = '', $db_conn = FALSE) {

        if (is_array($model)) {
foreach ($model as $babe) {
$this->model($babe);
}
return;
} if ($model == '') {
return;
} // model 是否在一个文件夹中,如果是的话,则分析路径和文件名
if (($last_slash = strrpos($model, '/')) !== FALSE) {
$path = substr($model, 0, $last_slash + 1); $model = substr($model, $last_slash + 1);
} if ($name = '') {
$name = $model;
} if (in_array($name, $this->_ci_models, TRUE)) {
return;
} $CI =& get_instance();
if (isset($CI->$name)) {
show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
} $model = strtolower($model); foreach ($this->_ci_model_paths as $mod_path) {
if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) {
continue;
} if ($db_conn !== FALSE AND ! class_exists('CI_DB')) {
if ($db_conn === TRUE) {
$db_conn = '';
} $CI->load->database($db_conn, FALSE, TRUE);
} if ( ! class_exists('CI_Model')) {
load_class('Model', 'core');
} require_once($mod_path.'models/'.$path.$model.'.php');
$model = ucfirst($model); $CI->$name = new $model(); $this->_ci_models[] = $name;
return;
} // 找不到模型
exit('Unable to locate the model you have specified: '.$model); }

1)通过 is_array 判断参数是否为数组,是的话,循环加载每一个模型,这样就可以通过传递数组一次加载多个模型。(这也是一个很好的技巧哦,传参数的时候就可以既传单个值,也可以传数组)

2)model 可以包含路径,这样更利于 model 的组织,比如用户模块的 基本信息model, 积分 model 都可以放在 user 文件夹下,所以将路径按 '/' 拆分,就可以得到二级 path 和 model 名。

3)加载 model 后,该model 实例会作为 $this 的成员变量,用什么标识呢?如果不提供的话,默认就用 model 的名字。

  比如  $this->load->model('news_model');

  加载后,可以通过 $this->news_model 来访问加载的模型。

4)规范化

  $this->load->model('News_model’); 这个用户想加载的类与 3)中一致,所以 $model 都会 strtolower 小写统一标记,这样不会出现两次加载了,另外实际在定义类的时候,news_model 对应的 class News_model;

  通过参考这些,我们可以提高写代码的优美度,也就是说用户可能在误输入大小写的情况下,依然保证能得到预期的效果。

3. 测试

  根据前述讲述,针对上一节的代码,本次新加入的代码包括 Loader.php , Controller.php, Model.php( 暂时为空)

  Welcome 类要继承 CI_Controller 类如下所示(放在 controllers 目录下)

<?php

class welcome extends CI_Controller {

    function hello() {
echo 'My first Php Framework!';
} function saysomething($str) {
$this->load->model('test_model'); $info = $this->test_model->get_test_data(); echo $info;
}
}

为了测试 model 新建一个 models/test_model.php 文件,然后写入

<?php

class Test_model extends CI_Model {

    function get_test_data() {
return 'People you want in our model is Zhangzhenyu';
} }

其中 CI_Model 暂时可以为空, 在 core/Model.php 下定义一个 CI_Model 的空类即可,以保证程序的正确执行。

主执行文件也需要做相应的更改如下:

require('core/Controller.php');

function &get_instance() {
return CI_Controller::get_instance();
} require('controllers/'.$class.'.php'); $CI = new $class(); call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));

4. 测试结果

访问 http://localhost/learn-ci/index.php/welcome/hello

输出 People you want in our model is Zhangzhenyu

具体代码参见 https://github.com/zhenyu-whu/learn-ci

一步一步重写 CodeIgniter 框架 (5) —— 实现Controller,并加载Model的更多相关文章

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

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

  2. 一步一步重写 CodeIgniter 框架 (12) —— 代码再重构,回归 CI

    第一课中搭建的基本的 框架模型, 只有一个 index.php 作为执行文件,按这种方式最不稳定的因素就是路径的问题. 我们经常需要通过合适的参数,比如 load_class('output') 或 ...

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

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

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

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

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

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

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

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

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

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

  8. 插件化框架解读之so 文件加载机制(四)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 提问 本文的结论是跟着 System.loadlibrary() ...

  9. 插件化框架解读之Android 资源加载机制详解(二)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680Android提供了一种非常灵活的资源系统,可以根据不同的条件提供 ...

随机推荐

  1. QT renered html for js

    voidMainWindow::on_pushButton_clicked() { QStringurl="http://www.baidu.com"; url="htt ...

  2. Android记录4--自定义ToggleButton+用SharedPreferences保存用户配置

    Android记录4--自定义ToggleButton+用SharedPreferences保存用户配置 2013年8月14日Android记录 很多应用都会有用户设置,用户的一些偏好可以由用户来决定 ...

  3. [置顶] Asp.Net底层原理(一、浏览器和服务器的交互原理)

    …… 一.浏览器和服务器的交互原理 二.写自己的"迷你"Asp.net框架 三.Asp.Net的请求与响应过程 1.在此之前,首先简单的模拟一下我们去请求一个网址的时候,浏览器和服 ...

  4. windows上运行npm Error: ENOENT, stat 'C:\Users\

    node 中 npm报错 Error: ENOENT, stat C:\Users\Administrator\AppData\Roaming\npm 报错原因可能是修改了node的默认安装路径.于是 ...

  5. C# Best Practices - Creating Good Methods

    How to Define a Method Identify the problem => Define the single purpose => Specify the inputs ...

  6. linux driver: input子系统

    <韦东山Linux视频第2期_从零写驱动\第13课第1节 输入子系统概念介绍_P.wmv> 本视频对输入子系统的结构进行了详细的剖析,通过本视频,可以了解到input核心包括了设备和han ...

  7. MD5校验及其c实现

    那么MD5校验是什么? 一般软件或者说文件都有自己的固定文件格式或者架构信息,说简单一点就是.”世界上没有完全相同的2片叶子” ,因为MD5是一种不可逆的加密算法. 那么对于某些网上公开下载的软件,视 ...

  8. php随笔11-Thinkphp常用系统配置大全

    Thinkphp常用配置  CHECK_FILE_CASE -- windows环境下面的严格检查大小写. /* 项目设定 */     'APP_DEBUG'    => false, // ...

  9. Python学习之路——迭代器、生成器、算法基础、正则

    一.迭代器: 迭代器是访问集合元素的一种方式. 迭代器对象是从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. 另外,迭代 ...

  10. oracle累计求和

    //将当前行某列的值与前面所有行的此列值相加,即累计求和: //方法一: with t as(      select 1 val from dual union all      select 3 ...