注解路由最省事但需清缓存,yaml更适合中大型项目;symfony 5.2+推荐#[route]属性,必须装annotations扩展、清缓存、正则用单引号;yaml集中管理、热更新,常用于主干路由导入注解控制器。

用注解最省事,但YAML更适合中大型项目——不是谁更“高级”,而是谁更可控、更易协作、更少踩坑。
注解路由:写在控制器里,改完要清缓存
Symfony 5.2+ 推荐用 #[Route] 属性,比如:
#[Route('/user/{id}', name: 'app_user_show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{ /* ... */ }
注意三点:
- 必须先装扩展:
composer require annotations - 每次改了
#[Route],都要手动清缓存:php bin/console cache:clear,否则新路由不生效 -
requirements里的正则必须用单引号包裹,'\d+'不能写成"\d+",否则 PHP 会把\d当作字符串转义处理
YAML路由:集中管理,改完即热更新(dev环境)
所有路由写在 config/routes.yaml,结构清晰,适合团队协作。例如:
app_user:
resource: '../../src/Controller/UserController.php'
type: annotation
prefix: /user
<p>api_routes:
resource: '../../src/Controller/Api/'
type: annotation
prefix: /api
</p>
这种写法本质是“用 YAML 导入注解”,兼顾集中管理和开发灵活性。关键点:
- YAML 中改路径、加前缀、换资源目录,不用清缓存,dev 环境下改完刷新就行
- 不推荐全 YAML 手写每条路由(太冗长),更适合做“主干路由组织”
- 如果某控制器方法需要特殊配置(比如只允许 POST),还是得回到注解或 XML
动态参数和可选参数:不加约束=留后门
{id} 默认匹配任意非斜杠字符,/user/..%2f..%2fetc%2fshadow 这类路径可能绕过预期逻辑。
安全写法只有两条:
- 强制加
requirements:requirements: { id: '\d+' }或注解中requirements: ['id' => '\d+'] - 可选参数必须路径和方法参数同步:
/blog/{slug?}+public function show(string $slug = 'home'),缺一不可
_query 参数嵌套:别传字符串,小心方括号解析失败
生成带查询参数的 URL 时,_query 只接受数组,不能传字符串:
- ❌ 错误:
['_query' => 'page=1&sort=asc']→ 直接抛InvalidParameterException - ✅ 正确:
['_query' => ['page' => 1, 'sort' => 'asc']] - ⚠️ 嵌套数组(如 filters[tags][])会被自动转成方括号格式,但某些 CDN、代理或前端库可能不规范解析——这时就得扁平化键名,比如用
filters_tags_0替代filters[tags][0]
真正容易被忽略的是:YAML 和注解不是二选一,而是分层配合。主干用 YAML 控制入口和前缀,细节用注解绑定动作,才是多数成熟项目的实际做法。











