本文目录导读:

我来为你详细介绍PHP实现伪静态路由的几种方法:
基础原理
伪静态是将动态URL转换为静态形式的URL,主要通过Web服务器配置和PHP路由实现。
Web服务器配置
Apache (.htaccess)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# 排除真实存在的文件
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# 将所有请求重定向到index.php
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
Nginx
server {
listen 80;
server_name example.com;
root /var/www/html;
# 排除存在的文件
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
PHP路由实现
简单路由类
<?php
class Router {
private $routes = [];
private $params = [];
// 注册路由规则
public function add($method, $pattern, $handler) {
$this->routes[] = [
'method' => $method,
'pattern' => $pattern,
'handler' => $handler
];
return $this;
}
// 处理GET请求
public function get($pattern, $handler) {
return $this->add('GET', $pattern, $handler);
}
// 处理POST请求
public function post($pattern, $handler) {
return $this->add('POST', $pattern, $handler);
}
// 匹配并执行路由
public function dispatch() {
$uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
// 去除查询字符串和开头的/
$uri = parse_url($uri, PHP_URL_PATH);
$uri = ltrim($uri, '/');
foreach ($this->routes as $route) {
if ($route['method'] === $method) {
$pattern = $this->convertToRegex($route['pattern']);
if (preg_match($pattern, $uri, $matches)) {
array_shift($matches);
$this->params = $matches;
// 调用控制器方法
list($controller, $action) = explode('@', $route['handler']);
$this->callAction($controller, $action, $matches);
return;
}
}
}
// 404处理
$this->notFound();
}
// 转换路由规则为正则
private function convertToRegex($pattern) {
// 将 {id} 转换为正则表达式
$pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $pattern);
return "/^" . str_replace('/', '\/', $pattern) . "$/";
}
// 调用控制器方法
private function callAction($controller, $action, $params) {
$controllerClass = ucfirst($controller) . 'Controller';
if (class_exists($controllerClass)) {
$instance = new $controllerClass();
if (method_exists($instance, $action)) {
call_user_func_array([$instance, $action], $params);
return;
}
}
$this->notFound();
}
// 404页面
private function notFound() {
http_response_code(404);
echo "404 Not Found";
}
}
使用示例
<?php
// index.php
require_once 'Router.php';
$router = new Router();
// 定义路由规则 (伪静态)
$router->get('/', 'home@index');
$router->get('articles/{id}', 'article@show');
$router->get('category/{name}/{page}', 'category@show');
$router->post('user/login', 'user@login');
// 模拟控制器
class HomeController {
public function index() {
echo "首页";
}
}
class ArticleController {
public function show($id) {
echo "显示文章ID: " . $id;
}
}
class CategoryController {
public function show($name, $page = 1) {
echo "分类: $name, 页码: $page";
}
}
class UserController {
public function login() {
echo "处理登录";
}
}
// 执行路由
$router->dispatch();
高级路由实现(带参数类型约束)
<?php
class AdvancedRouter {
private $routes = [];
private $middleware = [];
// 添加带约束的路由规则
public function add($method, $pattern, $handler, $constraints = []) {
$this->routes[] = [
'method' => $method,
'pattern' => $pattern,
'handler' => $handler,
'constraints' => $constraints
];
return $this;
}
// 解析路由参数
private function parseParams($pattern, $uri) {
$params = [];
$patternSegments = explode('/', trim($pattern, '/'));
$uriSegments = explode('/', trim($uri, '/'));
foreach ($patternSegments as $key => $segment) {
if (isset($uriSegments[$key])) {
if (strpos($segment, '{') === 0) {
// 提取参数名
preg_match('/\{(\w+)\}/', $segment, $matches);
$paramName = $matches[1];
$params[$paramName] = urldecode($uriSegments[$key]);
} elseif ($segment !== $uriSegments[$key]) {
return false;
}
} else {
return false;
}
}
return $params;
}
// 生成URL(反解析)
public function url($name, $params = []) {
foreach ($this->routes as $route) {
if ($route['hasName'] ?? false && $route['name'] === $name) {
$url = $route['pattern'];
foreach ($params as $key => $value) {
$url = str_replace("{$key}", $value, $url);
}
return '/' . $url;
}
}
return '#';
}
// 分组路由
public function group($prefix, $callback) {
// 保存当前分组前缀
$oldPrefix = $this->groupPrefix ?? '';
$this->groupPrefix = $oldPrefix . '/' . trim($prefix, '/');
call_user_func($callback, $this);
// 恢复旧前缀
$this->groupPrefix = $oldPrefix;
}
}
完整示例项目结构
project/
│
├── .htaccess
├── index.php
├── router/
│ └── Router.php
├── controllers/
│ ├── HomeController.php
│ ├── ArticleController.php
│ └── UserController.php
└── views/
├── home.php
└── article.php
缓存和性能优化
<?php
class CachedRouter {
private $cacheFile = 'route_cache.php';
private $routes;
public function __construct() {
// 检查是否有缓存的路由
if (file_exists($this->cacheFile)) {
$this->routes = require $this->cacheFile;
} else {
$this->routes = [];
}
}
public function add($pattern, $handler) {
$this->routes[$pattern] = $handler;
// 保存到缓存文件
$this->saveToCache();
return $this;
}
private function saveToCache() {
$data = "<?php return " . var_export($this->routes, true) . ";";
file_put_contents($this->cacheFile, $data);
}
public function dispatch() {
$uri = $_SERVER['REQUEST_URI'];
// 直接从数组查找
if (isset($this->routes[$uri])) {
return $this->callAction($this->routes[$uri]);
}
// 动态匹配
foreach ($this->routes as $pattern => $handler) {
if ($this->matchPattern($pattern, $uri)) {
return $this->callAction($handler);
}
}
$this->notFound();
}
}
使用Composer包
也可以使用PHP生态中成熟的路由库:
# 安装Slim框架 composer require slim/slim # 或使用FastRoute composer require nikic/fast-route
<?php
// 使用FastRoute示例
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/articles/{id:\d+}', 'article/show');
$r->addRoute('GET', '/category/{name}', 'category/show');
});
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// 404
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
// 405
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// 执行路由
break;
}
SEO友好的URL生成
<?php
function friendlyUrl($title) {
// 转换为小写
$slug = strtolower($title);
// 替换特殊字符
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
// 去除多余的连字符
$slug = trim($slug, '-');
return $slug;
}
// URL生成
$url = '/articles/' . friendlyUrl("PHP路由实现伪静态") . '-' . $articleId;
注意事项
- 安全性:路由参数需要适当过滤,防止SQL注入和XSS攻击
- 性能:合理使用路由缓存,避免正则表达式过度复杂
- 兼容性:确保服务器支持URL重写功能
- 维护性:保持路由规则清晰,定期清理无效路由
这就是PHP实现伪静态路由的主要方法,根据项目规模和需求,可以选择简单实现或使用成熟的框架。