手记 / 路由解析和路由请求分发

路由解析和路由请求分发

2天前5浏览0评论

一.路由解析

    首先在老师的代码中,发现了个小问题,就是在解析路由时,没有对pathInfo只有一个参数,两个参数,和没有参数时做默认值设定,我添加了一下,然后发现只有一个参数(模块),或者没有参数的时候,获取默认模块始终是空,于是添加了个判断$_SERVER['QUERY_STRING']不为空在进行下面操作,解决了这个问题. 

    路由解析就是通过系统变量$_SERVER['QUERY_STRING']的值来进行操作,将它的值以'/'分割成为数组(explode('/','进行去除左右两侧'/'并且改为小写的$_SERVER['QUERY_STRING的值']')),前三个数组元素的值依次为[模块][控制器][方法],之后的为参数,参数必须要成对出现,否则放弃此参数array_slice($queryArr,3);.

代码如下 麻烦老师检查一下看看是否正确 

namespace hero;

class Route
{
    //路由配置信息
    protected $route = [];

    //PATHINFO信息
    protected $pathInfo = [];
//    public $pathInfo = [];

    //URL参数
    protected $params = [];
//    public $params = [];

    //构造方法
    public function __construct($route)
    {
        //用路由配置初始化
        $this->route = $route;
        //设置默认pathInfo,也就是默认操作
        $this->pathInfo = $route;
    }

    //解析路由
    public function parse($queryStr='')
    {
        //  /admin/user/add/name/peter/age/30
        //$this->>pathInfo = ['module'=>'admin','controller'=>'user','action'=>'add]
        // 参数数组:$this->params = ['name'='peter','age'=>30]

        //第一步:将查询字符串前后的/去掉,在按照分隔符/拆分到数组中

        //判断$_SERVER['QUERY_STRING'] 值不为''的时候才进行执行,为空进行字符串分割也会分割成一个空元素的数组,导致出现一个长度的默认模块为''的问题,为空则使用默认$this->pathInfo = $route 在构造函数中已经写入默认值
        if(!$queryStr == ''){
            $queryStr = trim(strtolower($queryStr),'/');
            // 以'/'来分割字符串,成为三个数组
            $queryArr = explode('/',$queryStr);

            //第二步:解析出$queryArr数组中的内容(模块,控制器,操作,参数);
            switch (count($queryArr))
            {
                //没有参数,则使用默认的模块/控制器/操作
                case 0:    //为0则直接为默认值  默认值在构造函数中设置了
//                $this->pathInfo = $this->route;
                    break;
                //只有一个参数:用户只提供了模块,控制器和方法使用默认值
                case 1:    //默认值在构造函数中设置了 ,一个参数的值则覆盖默认参数
//                $this->pathInfo = $this->route;
                    $this->pathInfo['module'] = $queryArr[0];
                    break;
                //二个参数:模块和控制器自定义,操作是默认的
                case 2:    //2个参数同理   覆盖两个
//                $this->pathInfo = $this->route;
                    $this->pathInfo['module'] = $queryArr[0];
                    $this->pathInfo['controller'] = $queryArr[1];
                    break;
                //三个参数:模块控制器方法全部自定义
                case 3:
                    $this->pathInfo['module'] = $queryArr[0];
                    $this->pathInfo['controller'] = $queryArr[1];
                    $this->pathInfo['action'] = $queryArr[2];
                    break;
                //对参数进行处理
                default :
                    $this->pathInfo['module'] = $queryArr[0];
                    $this->pathInfo['controller'] = $queryArr[1];
                    $this->pathInfo['action'] = $queryArr[2];

                    //从pathInfo数组的索引3开始,将剩余的元素全部作为参数处理
                    $arr = array_slice($queryArr,3);
                    //键值对必须成对出现,所以每次递增2
                    for($i=0;$i< count($arr);$i += 2){
                        //如果没有第二个参数,则放弃
                        if(isset($arr[$i+1])){
                            $this->params[$arr[$i]] = $arr[$i+1];
                        }
                    }
                    break;
            }
            //返回当前路由类的实例对象,主要是方便链式效应:$route->parse()->worm()
            return $this;
        }

    }

    //请求分发
    public function dispatch()
    {
        //生成的带有命名空间的控制器类名称: app\模块\controller\控制器类
        //类名称应该与类文件所在的绝对路径一一对应,这样才可以实现自动映射,方便以后自动加载
        //模块名称
        $module = $this->pathInfo['module'];

        //控制器名称
        $controller = 'app\\'. $module .'\controller\\'. ucfirst($this->pathInfo['controller']);

        //操作名
        $action = $this->pathInfo['action'];

        if(!method_exists($controller,$action)){
            $action = $this->route['action'];
            header('Location:/');
        }

        //将用户的请求分发到指定的控制器和对应的操作方法上
        return call_user_func_array([new $controller,$action],$this->params);
    }
    //获取pathinfo信息
    public function getPathInfo()
    {
        return $this->pathInfo;
    }
    //获取route信息
    public function getRoute()
    {
        return $this->route;
    }
    //获取控制器名称
    public function getController()
    {
        return 'app\\'. $this->pathInfo['module'] .'\controller\\'. ucfirst($this->pathInfo['controller']);

    }
}
$config = require 'config.php';
$route = new Route($config['route']);
var_dump($_SERVER['QUERY_STRING']);

$route->parse($queryStr);
//print_r($route->pathInfo);
//print_r($route->params);
//var_dump($_SERVER['QUERY_STRING']);
//测试请求分发
require __DIR__.'/../app/admin/controller/Index.php';

//进行请求分发
echo $route->dispatch();
echo '<pre>';
//获取静态成员
echo $route->getController();
echo '<br>';
var_dump($route->getPathInfo());

1.png

3.png

二.请求分发

    请求分发个人理解就是将解析后的$pathInfo 等值,传入call_user_func_array()中来执行.有了前面的路由解析操作之后就简单的多了,要注意的是控制器类的命名空间要拼接,注意转义'\' 和控制器首字符大写ucfirst()

    2.png







相关标签:PHP
    0推荐

      作者的热门手记

      PHP中文网

      未登录