- 路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源
- 实现原理:检测url的变化,截获url地址,从url中解析出控制器和方法、参数然后来匹配路由规则
方案1:GET请求,从查询字符串解析出控制器、方法、参数
-php代码演示
<?php
//导入助手函数
require __DIR__ . '/../helper.php';
$url = 'http://php.edu/0507/router/demo1.php?c=user&a=hello';
//* 查询字符串:url问号后面的键值对:c=user&a-hello
//1. parse_url() 本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。
p(parse_url($url)['query']);
//? 2. $_SERVER['REQUEST_URI'],$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。'REQUEST_URI',URI 用来指定要访问的页面。
p($_SERVER['REQUEST_URI']);
p(parse_url($_SERVER['REQUEST_URI'])['query']);
//3. $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'])['query']
p($_SERVER['QUERY_STRING']);
//为处理方便,将字符串转为数组
// parse_str parse_str(string $string, array &$result): void
//如果 string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了 result 则会设置到该数组里 )。
// c = user & a = hello ===> ['c'=>'user', 'a'=>'hello']
parse_str($_SERVER['QUERY_STRING'], $params);
p($params);
// 过虑一下空值
$params = array_filter($params);
echo '<hr color=red >';
// 路由测试
class UserController
{
public static function hello($id = 1, $name = 'zhu')
{
return "<h3>Hello id=$id, name=$name</h3>";
}
}
// 约定: get参数中
// c 表示控制器
// a 表示控制器中的方法
$controller = ucfirst(array_shift($params)) . 'Controller';
$action = array_shift($params);
// http://php.edu/0507/router/demo1.php?c=user&a=hello&id=12&name=peter
echo call_user_func_array([$controller, $action], $params);
?>
助手函数文件helper.php代码
<?php
function p($name)
{
$type = gettype($name);
switch (strtolower($type)) {
case 'string':
case 'integer':
case 'double':
echo $name .'<br>';
break;
case 'null':
case 'boolean':
echo var_export($name) . '<br>';
break;
case 'object':
case 'array':
printf('<pre>%s</pre>',print_r($name,true));
break;
default:
echo '未定义类型';
}
}
?>
主流路由解决方案:pathinfo
- pathinfo() 返回一个关联数组包含有 path 的信息
$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是认证的类型。
- $_SERVER[‘PATH_INFO’] 包含由客户端提供的、跟在真实脚本名称之后并且在查询语句(query string)之前的路径信息,如果存在的话。例如,如果当前脚本是通过 URL http://www.example.com/php/path_info.php/some/stuff?foo=bar 被访问,那么 $_SERVER[‘PATH_INFO’] 将包含 /some/stuff
测试代码
<?php
require __DIR__ . '/../helper.php';
//! 主流路由解决方案:pathinfo pathinfo() 返回一个关联数组包含有 path 的信息
$url = 'http://php.edu/0507/router/demo2.php?c=user&a=hello';
p(pathinfo($url));
// $_SERVER['PATH_INFO']
// p($_SERVER['PATH_INFO']);
// 以单一入口为例
// index.php?m=模块,例如前台home,后台admin
// 单入口
// index.php/模块/控制器/方法
// index.php/module/controller/action
// 多入口
// 前台: index.php 做为入口 不需要模块, controller/action
// 后台: admin.php 做为入口, 不需要模块, controller/action
// 按顺序传递参数
$url = 'http://php.edu/0507/router/demo2.php/admin/user/index/5/admin';
p($_SERVER['PATH_INFO']);
p(explode('/', trim($_SERVER['PATH_INFO'], '/')));
$request1= explode('/',trim($_SERVER['PATH_INFO'],'/'));
// 将模块,控制器和方法解析出来
[$module, $controller, $action] = $request1;
require 'User.php';
// 调用: admin\User::index()
$className = $module . '\\' . ucfirst($controller);
$params1 = array_splice($request1, 3);
echo call_user_func_array([$className, $action], $params1);
// 键值对传参
// name/admin -> name = admin
//测试时输入下面URL
$url = 'http://php.edu/0507/router/demo2.php/admin/user/index/id/1/name/admin';
$request2= explode('/',trim($_SERVER['PATH_INFO'],'/'));
[$module, $controller, $action] = $request2;
$params2 = array_splice($request2, 3);
$arr = array_chunk($params2, 2);
$result =[];
foreach ($arr as $item) {
[$key, $value] = $item;
$result[$key] = $value;
}
$result = array_filter($result);
echo call_user_func_array([$className, $action], $result);
?>
User类文件代码 User.php
<?php
namespace admin;
use UserController;
class User
{
public static function index($id, $name)
{
printf('id = %d, name = %s', $id, $name);
}
}
?>