摘要:一.路由解析 首先在老师的代码中,发现了个小问题,就是在解析路由时,没有对pathInfo只有一个参数,两个参数,和没有参数时做默认值设定,我添加了一下,然后发现只有一个参数(模块),或者没有参数的时候,获取默认模块始终是空,于是添加了个判断$_SERVER['QUERY_STRING']不为空在进行下面操作,解决了这个问题. 
一.路由解析
首先在老师的代码中,发现了个小问题,就是在解析路由时,没有对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());
二.请求分发
请求分发个人理解就是将解析后的$pathInfo 等值,传入call_user_func_array()中来执行.有了前面的路由解析操作之后就简单的多了,要注意的是控制器类的命名空间要拼接,注意转义'\' 和控制器首字符大写ucfirst()
批改老师:韦小宝批改时间:2018-12-09 09:17:31
老师总结:好的!当时老师可能没有太注意哦!感谢反馈!