hyperf 路由中可选参数必须用 {id?} 语法配合 ->withdefault(['id' => null]) 显式设默认值,注解路由不支持该写法;未设默认值时即使带 ? 也会匹配失败或触发类型错误。

Hyperf 路由中定义可选参数的语法
Hyperf 的路由可选参数不是靠问号 ?(像 Express 那样),而是通过在参数名后加 ? 修饰符 + 给参数设默认值来实现。没有默认值的参数即使带 ? 也会报错或匹配失败。
正确写法是:/user/{id?} 必须配合 ->withDefault(['id' => 0]) 或类似方式提供默认值,否则该路由不会被注册或无法匹配无参数的请求。
-
{id?}表示 id 是可选的,但框架仍会尝试解析它;不传时需有兜底值 - 必须调用
withDefault(),且键名要和参数名完全一致(区分大小写) - 多个可选参数要全部列在
withDefault()中,缺一不可
实际注册路由时怎么写(@GetMapping / @PostMapping 场景)
注解路由下不能直接写 {id?},Hyperf 的注解解析器不支持这种语法。必须改用数组式定义,把参数声明为可选,并显式指定默认值。
错误写法:@GetMapping("/user/{id?}") → 注解解析失败,id 不会被识别为可选
正确写法:用 route 配置数组 + withDefault
Router::get('/user/{id}', [UserController::class, 'show'])
->withDefault(['id' => null]);
如果同时有多个可选参数,比如 /search/{keyword?}/{page?}/{limit?},就得这样写:
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
Router::get('/search/{keyword}/{page}/{limit}', [SearchController::class, 'index'])
->withDefault([
'keyword' => '',
'page' => 1,
'limit' => 20
])
可选参数不设默认值会发生什么
没设 withDefault() 时,Hyperf 会认为这个参数是必填的,即使写了 {id?}。访问 /user/ 会 404,而不是走默认逻辑。
更隐蔽的问题是:当控制器方法参数类型声明为 int $id = 0,但路由没配 withDefault,Hyperf 仍会尝试从 URL 提取 id —— 提取不到就传 null,导致类型错误:TypeError: Argument 1 passed to show() must be of the type int, null given。
- 路由层的默认值(
withDefault)和 PHP 方法参数默认值是两回事,不能互相替代 - Hyperf 在匹配阶段就要求所有命名参数都有值(哪怕为
null),否则跳过该路由 - 建议始终让
withDefault的值与控制器参数默认值保持一致,避免类型冲突
正则约束下的可选参数怎么加
给可选参数加正则(比如只允许数字)时,不能写成 {id:\d+?} —— 这种写法无效,Hyperf 不支持在正则后加 ? 表示可选。
正确方式是分开处理:先保证参数可选({id?}),再用 where() 单独加约束,且约束只对“存在该参数时”生效:
Router::get('/user/{id?}', [UserController::class, 'show'])
->withDefault(['id' => null])
->where(['id' => '\d+']);
此时:/user/ 匹配成功(id 为 null);/user/123 匹配成功;/user/abc 404。
注意:where() 不会影响可选性,只过滤已提供的参数值。没传参数时,正则根本不会执行。
{id?} 就万事大吉,结果漏掉 withDefault() 导致路由静默失效或类型报错。










