一,环境准备
- PHP: 7.3.3 +
- severe: Apache
二,路由重写先前条件
我们要实现PHP处理路由请求的功能,就需要Apache打开路由重写,这是因为在默认情况下,Apache不会将所有请求都发送到PHP解释器进行处理,所以就需要使用.htaccess
拓展文件来告诉Apache你要进行路由重写!
一般情况下,
.htaccess
是隐藏的,如果你不做特殊处理,它是无法直接访问到的!
在你开始编写.htaccess
之前,你先要在Apache的配置文件中声明:
Apache
<Directory "/path/to/存放.htaccess文件的目录">
AllowOverride All
</Directory>
以此确保覆盖 htaccess 是被允许的,保证你可以正确地重写 URL!
接下来,开始编写.htaccess
,让Apache知道要将所有的请求都提交给index.php
来处理:
语句 | 功能 |
---|---|
RewriteEngine On | 这一行指示 Apache 启用 URL 重写引擎,这样才能开始使用重写规则 |
RewriteCond %{REQUEST_FILENAME} !-f | 这一行表示如果请求的文件名不是一个真实存在的文件,就继续进行重写 |
RewriteCond %{REQUEST_FILENAME} !-d | 这一行表示如果请求的文件名不是一个真实存在的目录,则继续进行重写 |
RewriteRule ^(.*)% index.php ?url=$1 [QSA,L] |
这一行指将任意的请求都交付给index.php处理 |
总结就是:
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
三,具体实现
接下来,我们开始编写路由器代码:
- 路由注册:
php
$routes = array(
'/' => array('controller' => 'UserController', 'method' => 'show', 'request_method' => 'GET')
);
我们定义一个路由列表,注册了一个路由/
在这个路由注册时,我们在后面定义了一个映射表,这个映射表的作用就是方便之后匹配对应的方法,就像上面这样,我们定义了controller
,method
,request_method
这几个映射,这几个映射的作用就是:当访问/
根路径的时候,控制器方法为UserController
,然后执行UserController
下的show
方法,并且请求方式为GET
请求。 但是光是这样,并不能让php知道我们到底要做什么,因为我们只是写了一个映射框架,php并不知道到底要怎么映射,所以接下来我们就要来编写这些方法的映射方法:
- 映射方法:
在映射开始之前,你需要做的第一件事就是获取请求的路由:
php
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$request_method = $_SERVER['REQUEST_METHOD'];
注意,此处的uri并没有写错,有小伙伴可能会问了,难道不应该是url吗?其实不然,URL(学名:统一资源定位器)它是 URI 的一种具体形式,用于定位和访问互联网上的资源,URL 包含了资源的位置信息,可以指示资源的协议、主机名、路径、查询参数等,例如
https://www.example.com/index.html
就是一个url,然而URI 包括了完整的 URL 路径和查询字符串,但不包括协议、主机名和端口等信息,举个例子,如果客户端发送了一个 HTTP 请求是GET /post.html?name=lightCat HTTP/1.1
,那么其中的request_uri
就是/post.html?name=lightCat
在服务器端,也就可以通过读取 request_uri 的值获取到客户端实际请求的资源路径和查询参数,从而进行相应的处理和响应!
拿到路由后,你就可以开始匹配路由了!
php
foreach ($routes as $route => $params) {}
首先,就是要对刚刚注册的路由进行拆分,而这一句就是对刚刚的路由进行拆分!刚刚注册的路由经过这一句解析后可以分别得到controller
,method
,request_method
分别对应的值:
$route
可以得到/
$params['controller']
可以得到UserController
- 以此类推就可以得到其他对应的值
接着:
php
foreach ($routes as $route => $params) {
if (preg_match('/^' . $regex . '$/', $request_uri, $matches) && $request_method === $params['request_method']) {
}
}
里面多了一个if判断语句,作用是判断请求 URI 与路由规则是否匹配,并且请求方法是否符合要求,如果符合就执行里面的函数:
为了满足对于动态参数的获取,我们要预留正则表达位置:
php
$regex = str_replace(':id', '([a-z]+)', $route);
$regex = str_replace('/', '\/', $regex);
以此允许它匹配字母,便于之后使用,你也可以在此替换此正则表达式,来匹配不同类型的参数!
获取控制器和方法名:
php
$controller_name = $params['controller'];
$method_name = $params['method'];
实例化控制器对象:
php
$controller = new $controller_name();
提取动态参数:
php
$params = array_slice($matches, 1);
调用对应的方法,并传递参数:
php
call_user_func_array(array($controller, $method_name), $params);
最后,如果匹配完了,就要结束此函数
php
break
总结一下,全部PHP代码就是:
php
<?php
$routes = array(
'/' => array('controller' => 'UserController', 'method' => 'show', 'request_method' => 'GET')
);
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$request_method = $_SERVER['REQUEST_METHOD'];
foreach ($routes as $route => $params) {
$regex = str_replace(':id', '([a-z]+)', $route);
$regex = str_replace('/', '\/', $regex);
if (preg_match('/^' . $regex . '$/', $request_uri, $matches) && $request_method === $params['request_method']) {
$controller_name = $params['controller'];
$method_name = $params['method'];
$controller = new $controller_name();
$params = array_slice($matches, 1);
call_user_func_array(array($controller, $method_name), $params);
break;
}
}
- 控制器:
针对/
路由的控制器我们只需要:
php
class UserController {
public function show() {
echo 'hello world';
}
}
就可以实现访问/
路径时执行对应的函数了!如果你需要获取路由动态数据,只需要根据你刚刚书写的正则表达式规则,修改路由和控制器就可以了,因为刚刚我写的路由正则表达式是:
php
$regex = str_replace(':id', '([a-z]+)', $route);
$regex = str_replace('/', '\/', $regex);
所以我只需要把注册的路径修改为:
php
'/:id' => array('controller' => 'UserController', 'method' => 'show', 'request_method' => 'GET')
再把控制器修改为:
php
class UserController {
public function show($id) {
echo $id;
}
}
就可以实现在访问:/a
时页面输出a
了。
如果你需要处理post请求也是可以的,只需要将注册的路由最后面的GET
改为POST
就可以了!
四,写在最后
如果你也喜欢这篇文章的话不要忘记点赞哦!
- 有任何问题请在评论区留言
- 欢迎各位来访lightCatCode社区
- 我的知乎主页
- lightCat-Studio Github
- QQ交流群: 894611246
- 我的邮箱:zry110522@163.com
感谢您的阅读!