前面两篇文章为了重点突出 CodeIgniter 框架的原理,程序的结构很乱,有不少全局变量,在这一课中咱们采用面向对象的方法对原先代码进行重构。php
到目前为止,程序主要完成的就是 URL 分析,并根据配置文件进行路由转换,也就是说咱们这里有两个对象,分别处理 URL 分析和路由转换。数组
1. URL 分析框架
URL 分析最主要的两个函数是 detect_uri 和 explode_uri ,考虑到 路由的须要,URL 类包含的成员变量有 函数
segments 数组 原始URL的分段信息测试
rsegments 数组 通过路由后的分段信息fetch
uri_string URL的路径信息,也就是 index.php 以后的路径ui
由上述分析及参考上一节的代码:this
1 <?php 2 3 /** 4 * URI Class 5 * 6 * 分析 URI, 并决定路由 7 */ 8 9 class CI_URI { 10 11 var $segments = array(); 12 13 var $uri_string; 14 15 var $rsegments; 16 17 function fetch_uri_string() { 18 if ($uri = $this->detect_uri()) { 19 $this->set_uri_string($uri); 20 return; 21 } 22 23 } 24 25 /** 26 * Set 27 * @param [type] $str [description] 28 */ 29 function set_uri_string($str) { 30 $this->uri_string = ($str == '/') ? '' : $str; 31 } 32 33 34 /** 35 * -------------------------------------------------------------------- 36 * 获取 uri ,并经过 uri 调用相应的方法 37 * -------------------------------------------------------------------- 38 */ 39 40 function detect_uri() { 41 42 if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) { 43 return ''; 44 } 45 46 $uri = $_SERVER['REQUEST_URI']; 47 if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { 48 $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); 49 } 50 51 if ($uri == '/' || empty($uri)) { 52 return '/'; 53 } 54 55 $uri = parse_url($uri, PHP_URL_PATH); 56 57 // 将路径中的 '//' 或 '../' 等进行清理 58 return str_replace(array('//', '../'), '/', trim($uri, '/')); 59 } 60 61 62 63 function explode_uri() { 64 65 foreach (explode('/', preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) { 66 $val = trim($val); 67 if ($val != '') { 68 $this->segments[] = $val; 69 } 70 } 71 } 72 73 }
2. Router 路由类url
路由类起的做用就是一个路由转换 set_routing ,并提供给外界获取转换后路由的接口如 fetch_class, fetch_method 等, 根据前面两篇的代码和思路,很容易写出以下的 Router 类。spa
其中最关键的就是 set_routing 函数,它被入口文件 index.php 执行,经过 URI 类分析得到 分段信息,并根据分析后的结果,得到转换后的路由,设置 class 和 method。
1 <?php 2 3 class CI_Router { 4 5 var $uri; 6 7 var $routes; 8 9 var $class; 10 11 var $method; 12 13 var $default_controller; 14 15 function __construct() { 16 global $URI; 17 18 $this->uri = &$URI; 19 } 20 21 function set_routing() { 22 23 if (is_file('routes.php')) { 24 include('routes.php'); 25 } 26 27 $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route; 28 unset($route); 29 30 $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : $this->routes['default_controller']; 31 32 $this->uri->fetch_uri_string(); 33 34 if ($this->uri->uri_string == '') { 35 return $this->set_default_controller(); 36 } 37 38 $this->uri->explode_uri(); 39 40 $this->parse_routes(); 41 } 42 43 44 function set_default_controller() { 45 46 } 47 48 function parse_routes() { 49 $uri = implode('/', $this->uri->segments); 50 51 if (isset($this->routes[$uri])) { 52 $rsegments = explode('/', $this->routes[$uri]); 53 54 return $this->set_request($rsegments); 55 } 56 } 57 58 function set_request($segments = array()) { 59 60 if (count($segments) == 0) { 61 return $this->set_default_controller(); 62 } 63 64 $this->set_class($segments[0]); 65 66 if (isset($segments[1])) { 67 $this->set_method($segments[1]); 68 } else { 69 $method = 'index'; 70 } 71 72 $this->uri->rsegments = $segments; 73 } 74 75 function set_class($class) { 76 $this->class = str_replace(array('/', '.'), '', $class); 77 } 78 79 /** 80 * Set the method 81 * 82 * @param string $method the method to execute 83 */ 84 function set_method($method) { 85 $this->method = $method; 86 } 87 88 /** 89 * Fetch the class 90 * 91 * @return string the class 92 */ 93 function fetch_class() { 94 return $this->class; 95 } 96 97 /** 98 * Fetch the method 99 * 100 * @return string the method 101 */ 102 function fetch_method() { 103 return $this->method; 104 } 105 }
3. 主入口文件逻辑
使用面向对象重构后,主入口文件只须要建立它们的实例,经过调用它们的方法,便可以处理最重要的工做,而后经过调用 call_user_fun_array 来执行。
1 <?php 2 /** 3 * 框架主入口文件,全部的页面请求均定为到该页面,并根据 url 地址来肯定调用合适的方法并显示输出 4 */ 5 require 'Router.php'; 6 require 'URI.php'; 7 8 9 $URI = new CI_URI(); 10 11 $RTR = new CI_Router(); 12 13 $RTR->set_routing(); 14 15 16 $class = $RTR->fetch_class(); 17 $method = $RTR->fetch_method(); 18 19 $CI = new $class(); 20 21 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); 22 23 class Welcome { 24 25 function hello() { 26 echo 'My first Php Framework!'; 27 } 28 29 function saysomething($str) { 30 echo $str.", I'am the php framework you created!"; 31 } 32 }
4. 测试
http://localhost/learn-ci/index.php/welcome/hello ,能够看到与第二课同样的输出结果
hello, I'am the php framework you created!