前面两篇文章为了重点突出 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

posted on 2015-10-16 21:13  铁马金戈007  阅读(70)  评论(0)    收藏  举报