Compiler passes是Symfony提供的“在程序被执行之前容器被编译时”操作服务定义的一种架构。

Compiler Pass优先级 

Contributed by
Guilhem N
in #18022.

容器被编译的过程是复杂的,它分为若干步骤,被称为“优化传递(optimization passes)”(如解析服务引用等)和“删除传递”(如删除无用的服务)。

当注册一个compiler pass时,你可以选择其“发生阶段”,这得益于addCompilerPass()方法的第二个可选参数:

1
2
// ...
$container->addCompilerPass(new CustomPass(), PassConfig::TYPE_AFTER_REMOVING);

但是,你却不能选择在当前的“容器编译阶段”,Compiler Pass的执行顺序,所以只能是按“Symfony先发现谁”来排序。在某些情况下,这是不被接受的,所以Symfony 3.2允许你设置Compiler Pass优先级

优先级被定义在addCompilerPass()方法的第三个参数。默认的优先级是0,这个值可以是任何正负整数。愈高的优先级,愈先被执行:

1
2
// ...
$container->addCompilerPass(new CustomPass(), PassConfig::TYPE_AFTER_REMOVING, 30);

找到打了标签的服务并对其排序 

Contributed by
Iltar van der Berg
in #18482.

Compiler Pass的一个常见需求是,找到每一个打了给定标签的服务,然后按其优先级来排序。Symfony框架本身的代码库中,某些部分就要用到这个功能,因此Symfony 3.2添加了一个trait,用于找到标签服务,并对其排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Before Symfony 3.2
class CustomPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $warmers = array();
        foreach ($container->findTaggedServiceIds('kernel.cache_warmer') as $id => $attributes) {
            $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
            $warmers[$priority][] = new Reference($id);
        }
 
        krsort($warmers);
        $warmers = call_user_func_array('array_merge', $warmers);
 
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// In Symfony 3.2
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
 
class CustomPass implements CompilerPassInterface
{
    use PriorityTaggedServiceTrait;
 
    public function process(ContainerBuilder $container)
    {
        $warmers = $this->findAndSortTaggedServices('kernel.cache_warmer', $container);
 
        // ...
    }
}