
symfony 默认将实现 `twig\loader\loaderinterface` 的服务自动注册为 twig 加载器,但其加载顺序由服务标签的 `priority` 值决定;通过显式声明带优先级的 `twig.loader` 标签,即可精确控制链式加载器(`chainloader`)中各 loader 的执行顺序。
在 Symfony 中,Twig 的默认加载器是 Twig\Loader\ChainLoader,它会按优先级(priority)从高到低依次尝试每个注册的 twig.loader 服务。优先级越高(数值越大),越早被调用——这与事件监听器或缓存标签的优先级逻辑一致。
要将 FilesystemLoader(Symfony 默认内置)置于最前,再是 LoaderB,最后是 LoaderA(即:FilesystemLoader → LoaderB → LoaderA),你需要确保:
- FilesystemLoader 本身不参与 twig.loader 标签排序(它是硬编码在 Twig 扩展中的基础 loader,始终位于链首);
- 自定义 loader 按需设置 priority:LoaderB 优先级高于 LoaderA。
✅ 正确做法是在 services.yaml 中显式声明标签并指定 priority:
# config/services.yaml
services:
App\Twig\LoaderA:
tags:
- { name: 'twig.loader', priority: 0 } # 最后尝试
App\Twig\LoaderB:
tags:
- { name: 'twig.loader', priority: 1 } # 中间尝试⚠️ 注意事项:
- 不要手动定义 twig.loader 或 twig.loader.chain 服务,否则会破坏 Symfony TwigBundle 的自动配置逻辑,极易引发循环依赖(如你遇到的“infinite recursion”);
- priority 默认为 0,未设 priority 的服务将按容器编译顺序加入链中(不可靠,应避免);
- FilesystemLoader 是 TwigBundle 内部注入的底层 loader,无需也不应打 twig.loader 标签——它天然位于 ChainLoader 的首位;
- 若使用 Symfony 5.3+ 且 PHP 8.0+,可改用 PHP 属性语法替代 YAML 标签:
// src/Twig/LoaderA.php
namespace App\Twig;
use Twig\Loader\LoaderInterface;
use Symfony\Contracts\Service\Attribute\AsTwigLoader;
#[AsTwigLoader(priority: 0)]
class LoaderA implements LoaderInterface
{
// ...
}? 小技巧:可通过调试命令验证最终顺序:
php bin/console debug:container --tag=twig.loader
输出中将按 priority 降序列出所有 loader,帮助你快速确认配置是否生效。
总结:无需编写 CompilerPass,也无需重写 ChainLoader;只需为每个自定义 loader 显式声明带 priority 的 twig.loader 标签,即可安全、简洁、符合 Symfony 最佳实践地控制 Twig 模板加载顺序。










