一步一步重写 CodeIgniter 框架 (5) —— 实现Controller,并加载Model
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的更多相关文章
- 一步一步重写 CodeIgniter 框架 (9) —— 使用 CodeIgniter 类库
通过前面几节的内容,我们从零开始搭建了一个非常方便的MVC框架,理解了 CodeIgniter 框架最核心的部分.然而一个框架的便利不仅仅在于提供一个MVC就可以了,它还必须具有较高的扩展性.下面将从 ...
- 一步一步重写 CodeIgniter 框架 (12) —— 代码再重构,回归 CI
第一课中搭建的基本的 框架模型, 只有一个 index.php 作为执行文件,按这种方式最不稳定的因素就是路径的问题. 我们经常需要通过合适的参数,比如 load_class('output') 或 ...
- 一步一步重写 CodeIgniter 框架 (6) —— 实现在控制器Controller中加载View
1. 控制器将模型类获得的数据,传递给视图进行显示,所以视图必须负责接收数据,另外重要的一点是当模型和视图分开后,多个模型的数据可以传递给一个视图进行展示,也可以说一个模型的数据在多个不同的视图中进行 ...
- 一步一步重写 CodeIgniter 框架 (4) —— load_class 管理多个对象实例的思路
我们使用CodeIgniter 框架最主要是想利用其 MVC 特性,将模型.视图分开,并通过控制器进行统一控制.在尝试实现 MVC 模式之前,我们将实现其中一个对程序结构非常有用的技巧,就是 load ...
- 一步一步重写 CodeIgniter 框架 (3) —— 用面向对象重构代码
前面两篇文章为了重点突出 CodeIgniter 框架的原理,程序的结构很乱,有很多全局变量,在这一课中我们采用面向对象的方法对原先代码进行重构. 到目前为止,程序主要完成的就是 URL 分析,并根据 ...
- 一步一步重写 CodeIgniter 框架 (1) —— url 如何映射到具体的方法
CodeIgniter 框架最显著的特征就是 MVC 模式,它的做法就是提取 url 中的'分段', 映射到某个类的某个方法,从而由该方法来输出最终显示的页面内容.那么我们第一课中就是实现一个这样的原 ...
- 一步一步重写 CodeIgniter 框架 (11) —— 使用 CodeIgniter 函数库
在完成了CI框架的类库扩展后,很自然我们就会想到函数库的扩展.函数库的扩展在 CI 中称为 helper 函数与类有不同的地方,它不能继承,只能覆盖或者添加新的函数,或者直接完全新定义的一组函数. 由 ...
- 插件化框架解读之so 文件加载机制(四)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 提问 本文的结论是跟着 System.loadlibrary() ...
- 插件化框架解读之Android 资源加载机制详解(二)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680Android提供了一种非常灵活的资源系统,可以根据不同的条件提供 ...
随机推荐
- QT renered html for js
voidMainWindow::on_pushButton_clicked() { QStringurl="http://www.baidu.com"; url="htt ...
- Android记录4--自定义ToggleButton+用SharedPreferences保存用户配置
Android记录4--自定义ToggleButton+用SharedPreferences保存用户配置 2013年8月14日Android记录 很多应用都会有用户设置,用户的一些偏好可以由用户来决定 ...
- [置顶] Asp.Net底层原理(一、浏览器和服务器的交互原理)
…… 一.浏览器和服务器的交互原理 二.写自己的"迷你"Asp.net框架 三.Asp.Net的请求与响应过程 1.在此之前,首先简单的模拟一下我们去请求一个网址的时候,浏览器和服 ...
- windows上运行npm Error: ENOENT, stat 'C:\Users\
node 中 npm报错 Error: ENOENT, stat C:\Users\Administrator\AppData\Roaming\npm 报错原因可能是修改了node的默认安装路径.于是 ...
- C# Best Practices - Creating Good Methods
How to Define a Method Identify the problem => Define the single purpose => Specify the inputs ...
- linux driver: input子系统
<韦东山Linux视频第2期_从零写驱动\第13课第1节 输入子系统概念介绍_P.wmv> 本视频对输入子系统的结构进行了详细的剖析,通过本视频,可以了解到input核心包括了设备和han ...
- MD5校验及其c实现
那么MD5校验是什么? 一般软件或者说文件都有自己的固定文件格式或者架构信息,说简单一点就是.”世界上没有完全相同的2片叶子” ,因为MD5是一种不可逆的加密算法. 那么对于某些网上公开下载的软件,视 ...
- php随笔11-Thinkphp常用系统配置大全
Thinkphp常用配置 CHECK_FILE_CASE -- windows环境下面的严格检查大小写. /* 项目设定 */ 'APP_DEBUG' => false, // ...
- Python学习之路——迭代器、生成器、算法基础、正则
一.迭代器: 迭代器是访问集合元素的一种方式. 迭代器对象是从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. 另外,迭代 ...
- oracle累计求和
//将当前行某列的值与前面所有行的此列值相加,即累计求和: //方法一: with t as( select 1 val from dual union all select 3 ...