PHP自定义MVC框架实现URL多参数传递与控制器获取
实现带参数的PHP MVC路由匹配与参数传递
1. 路由规则的正则转换
首先要把带{id}、{secondid}这类占位符的路由规则,转换成能匹配真实URL的正则表达式。核心是将占位符替换为正则捕获组,同时保留URL的结构。
比如路由规则/product/{id}/{secondid},需要转换成正则#^/product/([^/]+)/([^/]+)$#:
^和$确保完全匹配整个URL路径,避免部分匹配导致的错误([^/]+)匹配任意非斜杠字符(作为参数值)#作为正则分隔符,避免和URL中的/冲突
可以写一个辅助函数自动完成转换:
private function convertRouteToRegex(string $route): string { // 把{param}格式的占位符替换为正则捕获组 $regex = preg_replace('/{([a-zA-Z0-9_]+)}/', '([^/]+)', $route); // 添加首尾锚点,确保完全匹配 return "#^$regex$#"; }
2. 路由匹配与参数提取
在handle方法中,先获取当前请求的URL路径,再遍历所有已注册的路由,用转换后的正则逐个匹配。匹配成功后,提取参数值并关联到对应的占位符名称。
完整的handle方法示例:
public function handle() { // 获取当前请求的URI(剔除查询字符串) $uri = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'); // 统一URI格式,添加开头斜杠 $uri = '/' . $uri; // 遍历所有已注册路由(假设$this->routes存储路由,格式为['路由规则' => ['控制器', '方法']]) foreach ($this->routes as $route => $action) { $regex = $this->convertRouteToRegex($route); if (preg_match($regex, $uri, $matches)) { // 移除第一个匹配项(整个URL),剩下的就是参数值 array_shift($matches); // 提取路由中的占位符名称 preg_match_all('/{([a-zA-Z0-9_]+)}/', $route, $paramNames); $paramNames = $paramNames[1]; // 将参数值与名称关联成数组(可选,也可直接按顺序传递) $params = array_combine($paramNames, $matches); // 实例化控制器并调用方法 list($controller, $method) = $action; $controllerInstance = new $controller(); // 两种参数传递方式: // 方式1:按顺序传值(适合控制器方法参数顺序与路由占位符一致) call_user_func_array([$controllerInstance, $method], $matches); // 方式2:传递关联数组(适合按参数名接收,需调整控制器方法) // $controllerInstance->$method($params); exit; // 匹配到路由后终止后续处理 } } // 未匹配到路由时返回404 http_response_code(404); echo "404 Not Found"; }
3. 控制器接收参数
根据选择的传递方式,控制器方法可以这样编写:
方式1:按顺序接收参数
class ProductController { public function show($id, $secondid) { echo "产品ID:{$id},二级ID:{$secondid}"; } }
方式2:接收关联数组参数
class ProductController { public function show($params) { echo "产品ID:{$params['id']},二级ID:{$params['secondid']}"; } }
4. 路由注册示例
确保路由注册格式正确:
$router = new Route(); // 注册带参数的路由 $router->get('/product/{id}/{secondid}', ['ProductController', 'show']); // 注册基础路由 $router->get('/about-us', ['PageController', 'about']);
额外优化点
- 参数类型限制:如果需要限制参数为数字(如ID),可以修改正则替换逻辑:
// 先替换{id}为数字捕获组,再处理其他占位符 $regex = preg_replace('/{id}/', '(\d+)', $route); $regex = preg_replace('/{([a-zA-Z0-9_]+)}/', '([^/]+)', $regex); - 兼容末尾斜杠:允许URL末尾带或不带斜杠,可修改正则为:
return "#^$regex/?$#";
内容的提问来源于stack exchange,提问作者Praful Rambade
相关产品推荐
相关产品推荐

