zoukankan      html  css  js  c++  java
  • 一步一步重写 CodeIgniter 框架 (3) —— 用面向对象重构代码

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

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

    1. URL 分析

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

    segments 数组 原始URL的分段信息

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

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

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

     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 路由类

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

    其中最关键的就是 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!

  • 相关阅读:
    python:一个比较有趣的脚本
    opencv:图像模糊处理
    opencv:基本图形绘制
    opencv:摄像头和视频的读取
    C++:lambda表达式
    opencv:傅里叶变换
    opencv:创建滑动条
    opencv:通过滑动条调节亮度和对比度
    【源码】防抖和节流源码分析
    【css】最近使用的两种图标字体库
  • 原文地址:https://www.cnblogs.com/zhenyu-whu/p/3176515.html
Copyright © 2011-2022 走看看