10000 [DependencyInjection] Sort the CompilerPass by priority · symfony/symfony@d17c1a9 · GitHub
[go: up one dir, main page]

Skip to content

Commit d17c1a9

Browse files
GuilhemNfabpot
authored andcommitted
[DependencyInjection] Sort the CompilerPass by priority
1 parent fce0299 commit d17c1a9

File tree

6 files changed

+139
-47
lines changed

6 files changed

+139
-47
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
3.2.0
5+
-----
6+
7+
* allowed to prioritize compiler passes by introducing a third argument to `PassConfig::addPass()`, to `Compiler::addPass` and to `ContainerBuilder::addCompilerPass()`
8+
49
3.0.0
510
-----
611

src/Symfony/Component/DependencyInjection/Compiler/Compiler.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,20 @@ public function getLoggingFormatter()
6565
/**
6666
* Adds a pass to the PassConfig.
6767
*
68-
* @param CompilerPassInterface $pass A compiler pass
69-
* @param string $type The type of the pass
68+
* @param CompilerPassInterface $pass A compiler pass
69+
* @param string $type The type of the pass
70+
* @param int $priority Used to sort the passes
7071
*/
71-
public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
72+
public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/**, $priority = 0*/)
7273
{
73-
$this->passConfig->addPass($pass, $type);
74+
// For BC
75+
if (func_num_args() >= 3) {
76+
$priority = func_get_arg(2);
77+
} else {
78+
$priority = 0;
79+
}
80+
81+
$this->passConfig->addPass($pass, $type, $priority);
7482
}
7583

7684
/**

src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function __construct()
3939
{
4040
$this->mergePass = new MergeExtensionConfigurationPass();
4141

42-
$this->optimizationPasses = array(
42+
$this->optimizationPasses = array(array(
4343
new ExtensionCompilerPass(),
4444
new ResolveDefinitionTemplatesPass(),
4545
new DecoratorServicePass(),
@@ -51,9 +51,9 @@ public function __construct()
5151
new AnalyzeServiceReferencesPass(true),
5252
new CheckCircularReferencesPass(),
5353
new CheckReferenceValidityPass(),
54-
);
54+
));
5555

56-
$this->removingPasses = array(
56+
$this->removingPasses = array(array(
5757
new RemovePrivateAliasesPass(),
5858
new ReplaceAliasByActualDefinitionPass(),
5959
new RemoveAbstractDefinitionsPass(),
@@ -64,98 +64,111 @@ public function __construct()
6464
new RemoveUnusedDefinitionsPass(),
6565
)),
6666
new CheckExceptionOnInvalidReferenceBehaviorPass(),
67-
);
67+
));
6868
}
6969

7070
/**
7171
* Returns all passes in order to be processed.
7272
*
73-
* @return array An array of all passes to process
73+
* @return CompilerPassInterface[]
7474
*/
7575
public function getPasses()
7676
{
7777
return array_merge(
7878
array($this->mergePass),
79-
$this->beforeOptimizationPasses,
80-
$this->optimizationPasses,
81-
$this->beforeRemovingPasses,
82-
$this->removingPasses,
83-
$this->afterRemovingPasses
79< F438 /td>+
$this->getBeforeOptimizationPasses(),
80+
$this->getOptimizationPasses(),
81+
$this->getBeforeRemovingPasses(),
82+
$this->getRemovingPasses(),
83+
$this->getAfterRemovingPasses()
8484
);
8585
}
8686

8787
/**
8888
* Adds a pass.
8989
*
90-
* @param CompilerPassInterface $pass A Compiler pass
91-
* @param string $type The pass type
90+
* @param CompilerPassInterface $pass A Compiler pass
91+
* @param string $type The pass type
92+
* @param int $priority Used to sort the passes
9293
*
9394
* @throws InvalidArgumentException when a pass type doesn't exist
9495
*/
95-
public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION)
96+
public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION/*, $priority = 0*/)
9697
{
98+
// For BC
99+
if (func_num_args() >= 3) {
100+
$priority = func_get_arg(2);
101+
} else {
102+
$priority = 0;
103+
}
104+
97105
$property = $type.'Passes';
98106
if (!isset($this->$property)) {
99107
throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
100108
}
101109

102-
$this->{$property}[] = $pass;
110+
$passes = &$this->$property;
111+
112+
if (!isset($passes[$priority])) {
113+
$passes[$priority] = array();
114+
}
115+
$passes[$priority][] = $pass;
103116
}
104117

105118
/**
106< 10000 /code>119
* Gets all passes for the AfterRemoving pass.
107120
*
108-
* @return array An array of passes
121+
* @return CompilerPassInterface[]
109122
*/
110123
public function getAfterRemovingPasses()
111124
{
112-
return $this->afterRemovingPasses;
125+
return $this->sortPasses($this->afterRemovingPasses);
113126
}
114127

115128
/**
116129
* Gets all passes for the BeforeOptimization pass.
117130
*
118-
* @return array An array of passes
131+
* @return CompilerPassInterface[]
119132
*/
120133
public function getBeforeOptimizationPasses()
121134
{
122-
return $this->beforeOptimizationPasses;
135+
return $this->sortPasses($this->beforeOptimizationPasses);
123136
}
124137

125138
/**
126139
* Gets all passes for the BeforeRemoving pass.
127140
*
128-
* @return array An array of passes
141+
* @return CompilerPassInterface[]
129142
*/
130143
public function getBeforeRemovingPasses()
131144
{
132-
return $this->beforeRemovingPasses;
145+
return $this->sortPasses($this->beforeRemovingPasses);
133146
}
134147

135148
/**
136149
* Gets all passes for the Optimization pass.
137150
*
138-
* @return array An array of passes
151+
* @return CompilerPassInterface[]
139152
*/
140153
public function getOptimizationPasses()
141154
{
142-
return $this->optimizationPasses;
155+
return $this->sortPasses($this->optimizationPasses);
143156
}
144157

145158
/**
146159
* Gets all passes for the Removing pass.
147160
*
148-
* @return array An array of passes
161+
* @return CompilerPassInterface[]
149162
*/
150163
public function getRemovingPasses()
151164
{
152-
return $this->removingPasses;
165+
return $this->sortPasses($this->removingPasses);
153166
}
154167

155168
/**
156169
* Gets all passes for the Merge pass.
157170
*
158-
* @return array An array of passes
171+
* @return CompilerPassInterface
159172
*/
160173
public function getMergePass()
161174
{
@@ -175,50 +188,69 @@ public function setMergePass(CompilerPassInterface $pass)
175188
/**
176189
* Sets the AfterRemoving passes.
177190
*
178-
* @param array $passes An array of passes
191+
* @param CompilerPassInterface[] $passes
179192
*/
180193
public function setAfterRemovingPasses(array $passes)
181194
{
182-
$this->afterRemovingPasses = $passes;
195+
$this->afterRemovingPasses = array($passes);
183196
}
184197

185198
/**
186199
* Sets the BeforeOptimization passes.
187200
*
188-
* @param array $passes An array of passes
201+
* @param CompilerPassInterface[] $passes
189202
*/
190203
public function setBeforeOptimizationPasses(array $passes)
191204
{
192-
$this->beforeOptimizationPasses = $passes;
205+
$this->beforeOptimizationPasses = array($passes);
193206
}
194207

195208
/**
196209
* Sets the BeforeRemoving passes.
197210
*
198-
* @param array $passes An array of passes
211+
* @param CompilerPassInterface[] $passes
199212
*/
200213
public function setBeforeRemovingPasses(array $passes)
201214
{
202-
$this->beforeRemovingPasses = $passes;
215+
$this->beforeRemovingPasses = array($passes);
203216
}
204217

205218
/**
206219
* Sets the Optimization passes.
207220
*
208-
* @param array $passes An array of passes
221+
* @param CompilerPassInterface[] $passes
209222
*/
210223
public function setOptimizationPasses(array $passes)
211224
{
212-
$this->optimizationPasses = $passes;
225+
$this->optimizationPasses = array($passes);
213226
}
214227

215228
/**
216229
* Sets the Removing passes.
217230
*
218-
* @param array $passes An array of passes
231+
* @param CompilerPassInterface[] $passes
219232
*/
220233
public function setRemovingPasses(array $passes)
221234
{
222-
$this->removingPasses = $passes;
235+
$this->removingPasses = array($passes);
236+
}
237+
238+
/**
239+
* Sort passes by priority.
240+
*
241+
* @param array $passes CompilerPassInterface instances with their priority as key.
242+
*
243+
* @return CompilerPassInterface[]
244+
*/
245+
private function sortPasses(array $passes)
246+
{
247+
if (0 === count($passes)) {
248+
return array();
249+
}
250+
251+
krsort($passes);
252+
253+
// Flatten the array
254+
return call_user_func_array('array_merge', $passes);
223255
}
224256
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,22 @@ public function loadFromExtension($extension, array $values = array())
298298
/**
299299
* Adds a compiler pass.
300300
*
301-
* @param CompilerPassInterface $pass A compiler pass
302-
* @param string $type The type of compiler pass
301+
* @param CompilerPassInterface $pass A compiler pass
302+
* @param string $type The type of compiler pass
303+
* @param int $priority Used to sort the passes
303304
*
304305
* @return ContainerBuilder The current instance
305306
*/
306-
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
307+
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/**, $priority = 0*/)
307308
{
308-
$this->getCompiler()->addPass($pass, $type);
309+
// For BC
310+
if (func_num_args() >= 3) {
311+
$priority = func_get_arg(2);
312+
} else {
313+
$priority = 0;
314+
}
315+
316+
$this->getCompiler()->addPass($pass, $type, $priority);
309317

310318
$this->addObjectResource($pass);
311319

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
15+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
17+
/**
18+
* @author Guilhem N <egetick@gmail.com>
19+
*/
20+
class PassConfigTest extends \PHPUnit_Framework_TestCase
21+
{
22+
public function testPassOrdering()
23+
{
24+
$config = new PassConfig();
25+
26+
$pass1 = $this->getMock(CompilerPassInterface::class);
27+
$config->addPass($pass1, PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
28+
29+
$pass2 = $this->getMock(CompilerPassInterface::class);
30+
$config->addPass($pass2, PassConfig::TYPE_BEFORE_OPTIMIZATION, 30);
31+
32+
$this->assertSame(array($pass2, $pass1), $config->getBeforeOptimizationPasses());
33+
}
34+
}

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Bridge\PhpUnit\ErrorAssert;
1818
use Symfony\Component\Config\Resource\ResourceInterface;
1919
use Symfony\Component\DependencyInjection\Alias;
20+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
2021
use Symfony\Component\DependencyInjection\ContainerBuilder;
2122
use Symfony\Component\DependencyInjection\ContainerInterface;
2223
use Symfony\Component\DependencyInjection\Definition;
@@ -284,10 +285,14 @@ public function testAddGetCompilerPass()
284285
{
285286
$builder = new ContainerBuilder();
286287
$builder->setResourceTracking(false);
287-
$builderCompilerPasses = $builder->getCompiler()->getPassConfig()->getPasses();
288-
$builder->addCompilerPass($this->getMock('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface'));
289-
290-
$this->assertCount(count($builder->getCompiler()->getPassConfig()->getPasses()) - 1, $builderCompilerPasses);
288+
$defaultPasses = $builder->getCompiler()->getPassConfig()->getPasses();
289+
$builder->addCompilerPass($pass1 = $this->getMock('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface'), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
290+
$builder->addCompilerPass($pass2 = $this->getMock('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface'), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
291+
292+
$passes = $builder->getCompiler()->getPassConfig()->getPasses();
293+
$this->assertCount(count($passes) - 2, $defaultPasses);
294+
// Pass 1 is executed later
295+
$this->assertTrue(array_search($pass1, $passes, true) > array_search($pass2, $passes, true));
291296
}
292297

293298
public function testCreateService()

0 commit comments

Comments
 (0)
0