php 框架 路由实现
路由实现的基本原理
路由是PHP框架中用于将HTTP请求映射到对应控制器和方法的机制。核心原理是通过解析URL,匹配预定义的路由规则,执行相应的回调函数或控制器方法。
基于正则表达式的路由匹配
使用正则表达式可以灵活定义路由规则。以下是一个简单的正则路由实现示例:
$routes = [
'/user/(\d+)' => 'UserController@show',
'/post/(\w+)' => 'PostController@show'
];
$requestUri = $_SERVER['REQUEST_URI'];
foreach ($routes as $pattern => $handler) {
if (preg_match('#^' . $pattern . '$#', $requestUri, $matches)) {
list($controller, $method) = explode('@', $handler);
call_user_func_array([new $controller, $method], array_slice($matches, 1));
break;
}
}
路由参数解析
现代框架通常支持命名参数的路由定义方式:
$route = '/user/{id}/profile/{tab}';
$path = '/user/123/profile/settings';
// 转换为正则表达式
$pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $route);
$pattern = '#^' . str_replace('/', '\/', $pattern) . '$#';
if (preg_match($pattern, $path, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
// $params 包含 ['id' => '123', 'tab' => 'settings']
}
路由组与中间件
路由组允许对多个路由应用共同的属性和中间件:
$router->group(['prefix' => 'admin', 'middleware' => 'auth'], function($router) {
$router->get('dashboard', 'AdminController@dashboard');
$router->get('users', 'AdminController@users');
});
RESTful 资源路由
资源路由自动生成CRUD路由:
$router->resource('photos', 'PhotoController');
// 生成以下路由:
// GET /photos index
// GET /photos/create create
// POST /photos store
// GET /photos/{photo} show
// GET /photos/{photo}/edit edit
// PUT/PATCH /photos/{photo} update
// DELETE /photos/{photo} destroy
路由缓存优化
生产环境通常会缓存路由以提高性能:
// 生成路由缓存
$router->setCacheFile(storage_path('routes.php'));
// 加载缓存路由
if (file_exists($cacheFile)) {
$router->setRoutes(require $cacheFile);
} else {
// 解析并缓存路由
$router->group([], require base_path('routes/web.php'));
$router->cacheCurrentRoutes();
}
动态路由加载
支持按需加载路由配置:
// 自动加载 routes 目录下的所有文件
foreach (glob(base_path('routes/*.php')) as $routeFile) {
$router->group([], function($router) use ($routeFile) {
require $routeFile;
});
}
路由匹配算法优化
使用更高效的路由匹配数据结构:
class RouteTrieNode {
public $children = [];
public $handlers = [];
}
class RouteTrie {
public $root;
public function __construct() {
$this->root = new RouteTrieNode();
}
public function insert($path, $handler) {
$node = $this->root;
$segments = explode('/', trim($path, '/'));
foreach ($segments as $segment) {
if (!isset($node->children[$segment])) {
$node->children[$segment] = new RouteTrieNode();
}
$node = $node->children[$segment];
}
$node->handlers[] = $handler;
}
}






