前面两篇文章为了重点突出 CodeIgniter 框架的原理,程序的结构很乱,有很多全局变量,在这一课中我们采用面向对象的方法对原先代码进行重构。

到目前为止,程序主要完成的就是 URL 分析,并根据配置文件进行路由转换,也就是说我们这里有两个对象,分别处理 URL 分析和路由转换。

1. URL 分析

URL 分析最主要的两个函数是 detect_uri 和 explode_uri ,考虑到 路由的需要,URL 类包含的成员变量有

segments 数组 原始URL的分段信息

rsegments 数组 经过路由后的分段信息

uri_string URL的路径信息,也就是 index.php 之后的路径

由上述分析及参考上一节的代码:

 <?php

 /**
* URI Class
*
* 分析 URI, 并决定路由
*/ class CI_URI { var $segments = array(); var $uri_string; var $rsegments; function fetch_uri_string() {
if ($uri = $this->detect_uri()) {
$this->set_uri_string($uri);
return;
} } /**
* Set
* @param [type] $str [description]
*/
function set_uri_string($str) {
$this->uri_string = ($str == '/') ? '' : $str;
} /**
* --------------------------------------------------------------------
* 获取 uri ,并通过 uri 调用相应的方法
* --------------------------------------------------------------------
*/ function detect_uri() { if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) {
return '';
} $uri = $_SERVER['REQUEST_URI'];
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) {
$uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
} if ($uri == '/' || empty($uri)) {
return '/';
} $uri = parse_url($uri, PHP_URL_PATH); // 将路径中的 '//' 或 '../' 等进行清理
return str_replace(array('//', '../'), '/', trim($uri, '/'));
} function explode_uri() { foreach (explode('/', preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) {
$val = trim($val);
if ($val != '') {
$this->segments[] = $val;
}
}
} }

2. Router 路由类

路由类起的作用就是一个路由转换 set_routing ,并提供给外界获取转换后路由的接口如 fetch_class, fetch_method 等, 根据前面两篇的代码和思路,很容易写出如下的 Router  类。

其中最关键的就是 set_routing 函数,它被入口文件 index.php 执行,通过 URI 类分析获得 分段信息,并根据分析后的结果,获得转换后的路由,设置 class 和 method。

 <?php

 class CI_Router {

     var $uri;

     var $routes;

     var $class;

     var $method;

     var $default_controller;

     function __construct() {
global $URI; $this->uri = &$URI;
} function set_routing() { if (is_file('routes.php')) {
include('routes.php');
} $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
unset($route); $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : $this->routes['default_controller']; $this->uri->fetch_uri_string(); if ($this->uri->uri_string == '') {
return $this->set_default_controller();
} $this->uri->explode_uri(); $this->parse_routes();
} function set_default_controller() { } function parse_routes() {
$uri = implode('/', $this->uri->segments); if (isset($this->routes[$uri])) {
$rsegments = explode('/', $this->routes[$uri]); return $this->set_request($rsegments);
}
} function set_request($segments = array()) { if (count($segments) == 0) {
return $this->set_default_controller();
} $this->set_class($segments[0]); if (isset($segments[1])) {
$this->set_method($segments[1]);
} else {
$method = 'index';
} $this->uri->rsegments = $segments;
} function set_class($class) {
$this->class = str_replace(array('/', '.'), '', $class);
} /**
* Set the method
*
* @param string $method the method to execute
*/
function set_method($method) {
$this->method = $method;
} /**
* Fetch the class
*
* @return string the class
*/
function fetch_class() {
return $this->class;
} /**
* Fetch the method
*
* @return string the method
*/
function fetch_method() {
return $this->method;
}
}

3. 主入口文件逻辑

使用面向对象重构后,主入口文件只需要创建它们的实例,通过调用它们的方法,即可以处理最重要的工作,然后通过调用 call_user_fun_array 来执行。

 <?php
/**
* 框架主入口文件,所有的页面请求均定为到该页面,并根据 url 地址来确定调用合适的方法并显示输出
*/
require 'Router.php';
require 'URI.php'; $URI = new CI_URI(); $RTR = new CI_Router(); $RTR->set_routing(); $class = $RTR->fetch_class();
$method = $RTR->fetch_method(); $CI = new $class(); call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); class Welcome { function hello() {
echo 'My first Php Framework!';
} function saysomething($str) {
echo $str.", I'am the php framework you created!";
}
}

4. 测试

http://localhost/learn-ci/index.php/welcome/hello ,可以看到与第二课一样的输出结果

hello, I'am the php framework you created!

一步一步重写 CodeIgniter 框架 (3) —— 用面向对象重构代码的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. 一步一步重写 CodeIgniter 框架 -- 原因和思路

    CodeIgniter 是一个非常轻量级的 PHP 框架,说是轻量级,最新版的代码只有不到2M. 其最重要的特点就是 MVC 模式来编写代码,如果大家看过一些用 PHP 来编写网站的书籍或教程,无一例 ...

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

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

  9. 一步一步重写 CodeIgniter 框架 (2) —— 实现简单的路由功能

    在上一课中,我们实现了简单的根据 URI 执行某个类的某个方法.但是这种映射没有扩展性,对于一个成熟易用的框架肯定是行不通的.那么,我们可以让 框架的用户 通过自定义这种转换来控制,用 CI 的术语就 ...

随机推荐

  1. React Native-目前最火的前端技术?

    做为一名产品经理,你是否遇到过这样的窘境,“帮我把字体调成 16号呗,颜色变成 #FFFF00FF,老大说这里最好改一下”,作为一名 app 的开发只能无奈但心里窃喜的告诉你,“只能等下个版本了,必须 ...

  2. mysql时间与字符串相互转换

    时间.字符串.时间戳之间的互相转换很常用,但是几乎每次使用时候都喜欢去搜索一下用法:本文整理一下三者之间的 转换(即:date转字符串.date转时间戳.字符串转date.字符串转时间戳.时间戳转da ...

  3. Clob对象转为字符串

    项目中遇到一个问题,对方公司把打印好的报表数据存到数据库中,实际上就是把html存在Oracle中,然后需要我们在社保系统里进行查询. 但是他们把数据存放在B数据库,而我们的社保系统用的数据库是B.A ...

  4. Hbase split的过程以及解发条件

    一.Split触发条件   1.  有任一一个Hfile的大小超过默认值10G时,都会进行split    2.  达到这个值不在拆分,默认为int_max,不进行拆分       3.compact ...

  5. 再次复习数据结构:c语言链表的简单操作

    最近呢,又要面临多次的数据结构与算法方面的试题了,而我呢,大概也重新温习c语言的基本要点快一个月了,主要是针对指针这货的角度在研究c语言,感觉又学到了不少. 现在c指针感觉知道点了,也就匆忙开展数据结 ...

  6. XML 反序列化为Model

    什么也不多说,直接贴代码 需要反序列的XML <?xml version='1.0' encoding='utf-8' ?> <GetCitiesListResponse> & ...

  7. 汇总:Linux下10款即时通讯客户端,skype

    aMSN 是一款功能强大的MSN(WLM)的客户端,支持皮肤.插件.系统托盘图标.摄像头.多帐号登录.离线信息等. Pidgin 不用说了,是GNOME下的IM客户端,支持AIM, Google Ta ...

  8. layer 的常用属性

    layer的各种属性代码示例: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading ...

  9. UVA 10341 Solve It 解方程 二分查找+精度

    题意:给出一个式子以及里面的常量,求出范围为[0,1]的解,精度要求为小数点后4为. 二分暴力查找即可. e^(-n)可以用math.h里面的exp(-n)表示. 代码:(uva该题我老是出现Subm ...

  10. BitNami一键安装Redmine

    1. 简单介绍 对于一个新手,假设严格依照官方文档来安装redmine,我想会"疯"掉的.有没有一种简便的方法.有滴,那就是BitNami. BitNami提供redmine的一键 ...