前面两篇文章为了重点突出 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!
文章来自:http://www.cnblogs.com/zhenyu-whu/p/3176515.html
浙公网安备 33010602011771号