前面兩篇文章爲了重點突出 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!