应统一用parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)提取路径并trim处理,再按/分割判断段数匹配REST层级,避免PATH_INFO配置依赖;正则必须加^和$锚定边界,如~^/users/(\d+)$~,防止误匹配。

PHP原生怎么写一个能匹配GET/POST的RESTful路由
靠$_SERVER['REQUEST_METHOD']和$_SERVER['PATH_INFO'](或$_SERVER['REQUEST_URI'])就能做,不需要框架。关键不是“怎么写”,而是“怎么避免把/users/123错当成/users/create”。
- 先用
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)提取路径,去掉查询参数和锚点 - 用
trim($path, '/')清理首尾斜杠,得到干净的users/123或posts - 按
/分割后判断段数:count($parts) === 1是集合级(GET /users),=== 2 && is_numeric($parts[1])是资源级(GET /users/123) - 别直接
switch($_SERVER['REQUEST_METHOD'])就完事——得先确认路径匹配成功,否则404要甩在方法判断之前
为什么$_SERVER['PATH_INFO']经常为空
因为没开Apache的AcceptPathInfo On,或者Nginx根本没配fastcgi_split_path_info。这时候$_SERVER['PATH_INFO']永远是空,硬用会全路由失效。
- Apache下检查
.htaccess有没有AcceptPathInfo On,没有就加;虚拟主机配置里也要确认全局开启 - Nginx必须显式拆分:在
location ~ \.php$块里加fastcgi_split_path_info ^(.+\.php)(/.+)$;,再用fastcgi_param PATH_INFO $fastcgi_path_info; - 更稳的做法是放弃
PATH_INFO,统一用parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)——它不依赖服务器配置
preg_match写REST路由时最容易写的三个错
正则不是越长越准,而是越贴近真实请求结构越可靠。常见错误都出在边界和贪婪上。
- 写
/users/(\d+)但没加^和$——结果/users/123/edit也命中,该进编辑逻辑却进了详情逻辑 - 用
.*匹配ID段:/users/(.*)/posts——.*会吞掉中间所有/,导致路径解析错层 - 忽略大小写却没加
i修饰符,导致/Users和/users被当两个路由,而你只注册了小写版本 - 正确写法示例:
~^/users/(\d+)$~(严格首尾)、~^/posts/([a-z0-9\-]+)$~i(ID允许短横线,且不区分大小写)
怎么让路由支持可选参数和查询参数共存
RESTful路径里的{id}是必填的,但?sort=created_at&limit=10这类查询参数永远走$_GET,别试图塞进正则里。
立即学习“PHP免费学习笔记(深入)”;
- 路径匹配只管
$_SERVER['PATH_INFO']或解析后的路径部分,$_GET单独处理——这是职责分离,也是性能关键 - 如果真需要“可选路径段”,比如
/users/archive和/users共用一个控制器,正则用/users(/archive)?,注意括号外的?表示整个分组可选 - 别在路由里解析
$_GET来决定控制器——那会让缓存、日志、权限校验全都绕弯路 - 实际分发时,把解析出的
$params = ['id' => 123]和$_GET合并传给控制器,而不是让控制器自己去$_GET捞
真正卡住人的从来不是“怎么写路由”,而是路径解析和服务器配置没对齐,或者正则边界没锁死。多打两次var_dump看$_SERVER里到底有啥,比翻文档快得多。










