一步一步重写 CodeIgniter 框架 (3) —— 用面向对象重构代码
前面两篇文章为了重点突出 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) —— 用面向对象重构代码的更多相关文章
- 一步一步重写 CodeIgniter 框架 (9) —— 使用 CodeIgniter 类库
通过前面几节的内容,我们从零开始搭建了一个非常方便的MVC框架,理解了 CodeIgniter 框架最核心的部分.然而一个框架的便利不仅仅在于提供一个MVC就可以了,它还必须具有较高的扩展性.下面将从 ...
- 一步一步重写 CodeIgniter 框架 (6) —— 实现在控制器Controller中加载View
1. 控制器将模型类获得的数据,传递给视图进行显示,所以视图必须负责接收数据,另外重要的一点是当模型和视图分开后,多个模型的数据可以传递给一个视图进行展示,也可以说一个模型的数据在多个不同的视图中进行 ...
- 一步一步重写 CodeIgniter 框架 (5) —— 实现Controller,并加载Model
CodeIgniter 框架采用MVC模式,而MVC模式中起纽带作用的就是C(控制器),在控制器的中通过加载模型获得数据,将数据传到视图中进行展示.本课将实现在控制器中加载模型. 1. 控制器的实现 ...
- 一步一步重写 CodeIgniter 框架 (4) —— load_class 管理多个对象实例的思路
我们使用CodeIgniter 框架最主要是想利用其 MVC 特性,将模型.视图分开,并通过控制器进行统一控制.在尝试实现 MVC 模式之前,我们将实现其中一个对程序结构非常有用的技巧,就是 load ...
- 一步一步重写 CodeIgniter 框架 (1) —— url 如何映射到具体的方法
CodeIgniter 框架最显著的特征就是 MVC 模式,它的做法就是提取 url 中的'分段', 映射到某个类的某个方法,从而由该方法来输出最终显示的页面内容.那么我们第一课中就是实现一个这样的原 ...
- 一步一步重写 CodeIgniter 框架 (12) —— 代码再重构,回归 CI
第一课中搭建的基本的 框架模型, 只有一个 index.php 作为执行文件,按这种方式最不稳定的因素就是路径的问题. 我们经常需要通过合适的参数,比如 load_class('output') 或 ...
- 一步一步重写 CodeIgniter 框架 -- 原因和思路
CodeIgniter 是一个非常轻量级的 PHP 框架,说是轻量级,最新版的代码只有不到2M. 其最重要的特点就是 MVC 模式来编写代码,如果大家看过一些用 PHP 来编写网站的书籍或教程,无一例 ...
- 一步一步重写 CodeIgniter 框架 (11) —— 使用 CodeIgniter 函数库
在完成了CI框架的类库扩展后,很自然我们就会想到函数库的扩展.函数库的扩展在 CI 中称为 helper 函数与类有不同的地方,它不能继承,只能覆盖或者添加新的函数,或者直接完全新定义的一组函数. 由 ...
- 一步一步重写 CodeIgniter 框架 (2) —— 实现简单的路由功能
在上一课中,我们实现了简单的根据 URI 执行某个类的某个方法.但是这种映射没有扩展性,对于一个成熟易用的框架肯定是行不通的.那么,我们可以让 框架的用户 通过自定义这种转换来控制,用 CI 的术语就 ...
随机推荐
- mysql 中的 IF 和 IFNULL 用法
IFNULL(expr1,expr2) 如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2.IFNULL()返回一个数字或字符串值,取决于它被使用的上下文环境. IF(S ...
- 高级UNIX环境编程3 FILE IO
POSIX中,STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO 对应0,1,2 每个打开的文件都有一个与其想关联的 "current file offset& ...
- perl post 带上请求头
my $url='https://www.zjcap.cn/business/dispatch_post.do?action=submitAdminLogin'; my $res = $ua-> ...
- 数据结构——二叉搜索树(Binary Search Tree)
二叉树(Binary Tree)的基础下 每个父节点下 左节点小,右节点大. 节点的插入: 若root==NULL则root=newnode 否则不断与节点值比较,较小则向左比较,较大则向右比较. 完 ...
- myeclipse设置凝视
Window-perferences--java--Code Style--Code Templates--Commments 类凝视:Types /** *@desc *@author haozk ...
- Android访问网络
Android中访问网络用的是HttpClient的方式,即Apache提供的一个jar包.安卓中继承了改jar包,所以安卓adt中不需要专门import该jar,直接就可以使用. 以下是MainAc ...
- 浏览器与服务器间的交互(客服端 <---> 服务器)
浏览器与服务器间的交互(客服端 <---> 服务器) 请求--->处理--->响应 对类HttpContext 内部成员的使用 例如 :Request .Response . ...
- CentOS6.5实现rsync+inotify实时同步
参考博文: 参考1:CentOS6.5实现rsync+inotify实时同步 参考2:inotify-tools+rsync实时同步文件安装和配置 CentOS 6.3下rsync服务器的安装与配置 ...
- 多玩YY聊天记录解析全过程
再来一发,现在开始! 下载安装YY,观察YY目录,很明显的发现了sqlite3.dll,这个数据库很多很多很多软件都在用,简单小巧且开源.删除sqlite3.dll 进入YY,历史记录不能正常显示,基 ...
- Android string.xml error: Apostrophe not preceded by \
Android string.xml error: Apostrophe not preceded by \ 遇到了这个错误,编译无法通过 error: Apostrophe not preceded ...