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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容