文档章节

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

Yomut
 Yomut
发布于 2016/07/15 17:14
字数 1330
阅读 10
收藏 0

 

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

 

1. 控制器的实现

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

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

复制代码

1 class CI_Controller {
 2 
 3     private static $instance;
 4 
 5     /**
 6      * Constructor
 7      */
 8     public function __construct()
 9     {
10         self::$instance =& $this;
11         
12         // Assign all the class objects that were instantiated by the
13         // bootstrap file (CodeIgniter.php) to local class variables
14         // so that CI can run as one big super object.
15         foreach (is_loaded() as $var => $class)
16         {
17             $this->$var =& load_class($class);
18         }
19 
20         $this->load =& load_class('Loader', 'core');
21 
22         $this->load->initialize();
23         
24         log_message('debug', "Controller Class Initialized");
25     }
26 
27     public static function &get_instance()
28     {
29         return self::$instance;
30     }
31 }

复制代码

它定义了一个静态成员变量,并在初始化时等于自己 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

本文转载自:http://www.cnblogs.com/zhenyu-whu/p/3254173.html

共有 人打赏支持
Yomut
粉丝 19
博文 191
码字总数 167789
作品 0
厦门
后端工程师
私信 提问
CodeIgniter 框架分析

入口文件 入口文件主要完成下列工作: 1) 指定 CodeIgniter 框架所在目录; 2) 定义 APPPATH 常量,指示应用程序文件根目录; 3) 载入 codeigniter/CodeIgniter.php 文件,启动框架。 codeig...

那些年我们一起
2012/08/10
0
17
使用 CodeIgniter 创建 Facebook 应用程序

本文向您演示了如何让 Facebook 示例应用程序与 PHP 框架 - CodeIgniter 共同工作。虽然有许多有关 Facebook 开发的好文章,当然,也有一些有关使用 CodeIgniter 来构建应用程序的好文章,但...

IBMdW
2011/07/12
1K
0
CodeIgniter框架环境配置

之前连续搭了好几个项目,觉得用CodeIgniter框架搭建项目已经非常熟悉了。今天想再单独弄一个环境,用作PHP技术的学习和实践平台,却发现之前“熟记”的过程都快放的差不多了,怎么都安装不成...

Claire_level
2012/05/14
0
0
CodeIgniter + uploadify 在 IE 下会话丢失问题的解决方案

最近需要学习并用CodeIgniter框架对一个项目进行二次开发,由于之前一直都是使用Symfony做项目,所以再换到CodeIgniter项目上还是比较顺畅的。不过相比较之下,感觉CodeIgniter比Symfony要轻...

random123
2014/06/23
0
0
CodeIgniter 3.0.1 RC 发布,PHP 的 MVC 框架

CodeIgniter 3.0.1 RC 发布,现已提供下载:https://github.com/bcit-ci/CodeIgniter/archive/3.0.1rc.zip。 CodeIgniter 是一个简单快速的PHP MVC 框架。EllisLab 的工作人员发布了 CodeIg...

oschina
2015/07/27
1K
13

没有更多内容

加载失败,请刷新页面

加载更多

为什么强烈建议大家使用枚举来实现单例

关于单例模式,我的博客中有很多文章介绍过。作为23种设计模式中最为常用的设计模式,单例模式并没有想象的那么简单。因为在设计单例的时候要考虑很多问题,比如线程安全问题、序列化对单例的...

群星纪元
26分钟前
8
0
Confluence 6 超过当前许可证期限进行升级

这个页面将会对你在进行 Confluence 升级的时候超过了当前许可证的期限进行升级的情况。 许可证警告 在升级的过程中,你将会在 Confluence 的应用程序日志(log file)中看到类似下面的错误提...

honeymoose
38分钟前
2
0
顶尖战略咨询公司常用分析模型

1、KANO模型 日本教授狩野纪昭(Noriaki Kano)构建出的kano模型。将影响用户满意度的因素划分为五个类型,包括: 魅力因素:用户意想不到的,如果不提供此需求,用户满意度不会降低,但当提供...

Moks角木
54分钟前
2
0
Linux iptables之mangle表使用案例

mangle表的用途 mangle表的主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由。 mangel表使用示例 示例1-策略路由1 内网的客户机通...

月下狼
今天
3
0
OSChina 周日乱弹 —— 兼职我想去学学布偶戏

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @clouddyy : 《火炎 - 女王蜂》 《火炎 - 女王蜂》 手机党少年们想听歌,请使劲儿戳(这里) @小鱼丁 :还在睡觉突然接到一个小哥哥电话“x...

小小编辑
今天
223
8

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部