摘要:一.路由解析 首先在老师的代码中,发现了个小问题,就是在解析路由时,没有对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
老师总结:好的!当时老师可能没有太注意哦!感谢反馈!