PHP路由实现伪静态

wen PHP项目 2

本文目录导读:

PHP路由实现伪静态

  1. 基础原理
  2. Web服务器配置
  3. PHP路由实现
  4. 高级路由实现(带参数类型约束)
  5. 完整示例项目结构
  6. 缓存和性能优化
  7. 使用Composer包
  8. SEO友好的URL生成
  9. 注意事项

我来为你详细介绍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;

注意事项

  1. 安全性:路由参数需要适当过滤,防止SQL注入和XSS攻击
  2. 性能:合理使用路由缓存,避免正则表达式过度复杂
  3. 兼容性:确保服务器支持URL重写功能
  4. 维护性:保持路由规则清晰,定期清理无效路由

这就是PHP实现伪静态路由的主要方法,根据项目规模和需求,可以选择简单实现或使用成熟的框架。

抱歉,评论功能暂时关闭!