PHP解析PATH_INFO模式URL的路由类

编码工作中框架给我们提供了很多便利,自己更多处理的是业务层的代码,而很少接触较为基础的东西。
趁最近有空,自己想着写了一个处理PATH_INFO模式URL的路由类。因为自己工作常用框架是TP5,所以有些风格习惯定义和TP5很像。
完整DEMO请参阅我的码云:https://gitee.com/VwenX/Router
下面是路由部分核心类,URL解析后用反射API处理参数然后调用对应方法。


// 定义常量
define('URL_PATH',isset($_SERVER['PATH_INFO']) ? preg_replace('/\/+/','/',strtolower($_SERVER['PATH_INFO'])) : '/');
define('APP_PATH', 'app');
define('Control_PATH', 'controller');

class Route
{
    
    // 路由规则
    private static $rules = [
                        'get'     => [],
                        'post'    => [],
                        'put'     => [],
                        'delete'  => [],
                        '*'       => []
                    ];
    /**
     * 绑定路由
     * @param  string $rule  路由规则
     * @param  string $route 路由地址
     * @param  string $type  请求类型
     * By.Vwen https://gitee.com/VwenX/Router
     */
    static function rule($rule, $route = '', $type = '*')
    {
        $rule = strtolower($rule);
        $rule = '/'==substr($rule,0,1) ? $rule : '/'.$rule;
        $route = strtolower($route);
        $type = strtolower($type);
        if ('*' == $type) {
            foreach (self::$rules as $key => $value) {
                self::$rules[$key][$rule] = $route;
            }
        }else{
            self::$rules[$type][$rule] = $route;
            self::$rules['*'][$rule] = $route;
        }
    }
    /**
     * 提供快捷绑定
     * 如 Route::get() Route::post()
     * 仅为概念简写,实际应用请按需修改及验证
     */
    static function __callStatic($func, $arguments)
    {
        $arguments[] = $func;
        self::rule(...$arguments);
    }
    /**
     * 解析当前请求URL
     * @return array    路由信息数组
     */
    static function parseUrl()
    {
        $analysis = ['status'=>404];
        $METHOD = strtolower($_SERVER['REQUEST_METHOD']);
        // 直接匹配
        if (isset(self::$rules[$METHOD][URL_PATH])) {
            $analysis['status'] = 200;
            $analysis['rule'] = URL_PATH;
            $analysis['route'] = self::$rules[$METHOD][URL_PATH];
        }else{
        // 列表匹配
            foreach (self::$rules[$METHOD] as $rule => $route) {
                if (substr($rule,-1)=='$' && substr_count($rule,'/')!=substr_count(URL_PATH,'/')) {
                        continue ;
                }
                $reg = '/^'.str_replace('/','\/',preg_replace('/:[a-z]+(?=\/|\$|$)/','\S+',$rule)).'/';
                if (!preg_match($reg,URL_PATH)) {
                    continue ;
                }
                $analysis['status'] = 200;
                $analysis['rule'] = $rule;
                $analysis['route'] = $route;
                break;
            }
        }
        // 处理未注册的路由 /M/C/A
        if (!isset($analysis['route'])) {
            $path_list = explode('/', trim( URL_PATH,'/'));
            $module = isset($path_list[0]) ? $path_list[0] : 'index';
            $Controller = isset($path_list[1]) ? $path_list[1] : 'index';
            $action = isset($path_list[2]) ? $path_list[2] : 'index';
            $analysis['rule'] = $analysis['route'] = '/'.$module.'/'.$Controller.'/'.$action;
        }
        // 获取路由参数
        if (isset($analysis['route'])) {
            $param = [];
            $rule_list = explode('/', $analysis['rule']);
            $path_list = explode('/', URL_PATH);
            if(strpos($analysis['rule'], ':')!==false){
                foreach ($rule_list as $key => $value) {
                    if (substr($value,0,1)==':') {
                        $param[trim($value,':$')] = $path_list[$key];
                    }
                }
            }
            // 获取剩余参数
            for ($i=count($rule_list); $i < count($path_list); $i+=2) { 
                if (isset($path_list[$i+1])) {
                    $param[$path_list[$i]] = $path_list[$i+1];
                }
            }
            $analysis['param'] = self::Params($param);
            // 在控制器方法传参中用 $req 获取请求参数
            $analysis['param']['req'] = $analysis['param'];
        }
        return $analysis;
    }
    /**
     * 处理请求参数
     * @param  array $param    PATH_INFO参数
     * @return array    
     */
    static function Params($param=[])
    {
        return array_merge($param,$_GET,$_POST);
    }
    /**
     * 生成URL
     * @param  string $route  路由地址 模块/控制器/方法
     * @param  array  $vars   参数数组
     * @param  string $method 按特定请求模式解析
     * @return string    处理好的URL
     */
    static function getUrl($route='',$vars=[],$method='*')
    {
        $route = strtolower(trim($route,'/'));
        $method = strtolower($method);
        $rule = array_search($route,self::$rules[$method]);
        if (!$rule) {
            return '';
        }
        $rule_list = explode('/', trim($rule,'/'));
        // 处理预定义参数
        if (strpos($rule, ':')!==false) {
            foreach ($rule_list as $key => $value) {
                if (strpos($value, ':')!==false) {
                    $rule_list[$key] = isset($vars[trim($value,':$')]) ? $vars[trim($value,':$')] : '';
                    if (isset($vars[trim($value,':$')])) unset($vars[trim($value,':$')]);
                }
            }
        }
        // 处理剩余参数
        if (strpos($rule, '$')==false && $vars != '') {
            foreach ($vars as $key => $value) {
                $rule_list[] = $key;
                $rule_list[] = $value;
            }
        }
        $rule = rtrim('/'.implode('/',$rule_list),'$');
        return $rule;
    }
}

你可能感兴趣的:(PHP解析PATH_INFO模式URL的路由类)