Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ead5a79

Browse files
[DI] Improve performance of removing/inlining passes
1 parent c81f88f commit ead5a79

16 files changed

+247
-124
lines changed

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ public function testPoolRefsAreWeak()
5555
$container->setAlias('clearer_alias', 'clearer');
5656

5757
$pass = new RemoveUnusedDefinitionsPass();
58-
$pass->setRepeatedPass(new RepeatedPass(array($pass)));
58+
foreach ($container->getCompiler()->getPassConfig()->getRemovingPasses() as $removingPass) {
59+
if ($removingPass instanceof RepeatedPass) {
60+
$pass->setRepeatedPass(new RepeatedPass(array($pass)));
61+
break;
62+
}
63+
}
5964
foreach (array(new CachePoolPass(), $pass, new CachePoolClearerPass()) as $pass) {
6065
$pass->process($container);
6166
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Definition;
1717
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18+
use Symfony\Component\DependencyInjection\ExpressionLanguage;
1819
use Symfony\Component\DependencyInjection\Reference;
20+
use Symfony\Component\ExpressionLanguage\Expression;
1921

2022
/**
2123
* @author Nicolas Grekas <[email protected]>
@@ -28,6 +30,9 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
2830
protected $container;
2931
protected $currentId;
3032

33+
private $processExpressions = false;
34+
private $expressionLanguage;
35+
3136
/**
3237
* {@inheritdoc}
3338
*/
@@ -42,6 +47,11 @@ public function process(ContainerBuilder $container)
4247
}
4348
}
4449

50+
protected function enableExpressionProcessing()
51+
{
52+
$this->processExpressions = true;
53+
}
54+
4555
/**
4656
* Processes a value found in a definition tree.
4757
*
@@ -63,6 +73,8 @@ protected function processValue($value, $isRoot = false)
6373
}
6474
} elseif ($value instanceof ArgumentInterface) {
6575
$value->setValues($this->processValue($value->getValues()));
76+
} elseif ($value instanceof Expression && $this->processExpressions) {
77+
$this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
6678
} elseif ($value instanceof Definition) {
6779
$value->setArguments($this->processValue($value->getArguments()));
6880
$value->setProperties($this->processValue($value->getProperties()));
@@ -169,4 +181,29 @@ protected function getReflectionMethod(Definition $definition, $method)
169181

170182
return $r;
171183
}
184+
185+
private function getExpressionLanguage()
186+
{
187+
if (null === $this->expressionLanguage) {
188+
if (!class_exists(ExpressionLanguage::class)) {
189+
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
190+
}
191+
192+
$providers = $this->container->getExpressionLanguageProviders();
193+
$this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
194+
if ('""' === substr_replace($arg, '', 1, -1)) {
195+
$id = stripcslashes(substr($arg, 1, -1));
196+
$arg = $this->processValue(new Reference($id));
197+
if (!$arg instanceof Reference) {
198+
throw new RuntimeException(sprintf('"%s::processValue()" must return a Reference when processing an expression, %s returned for service("%s").', get_class($this->currentId), is_object($arg) ? get_class($arg) : gettype($arg)));
199+
}
200+
$arg = sprintf('"%s"', $arg);
201+
}
202+
203+
return sprintf('$this->get(%s)', $arg);
204+
});
205+
}
206+
207+
return $this->expressionLanguage;
208+
}
172209
}

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

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1515
use Symfony\Component\DependencyInjection\ContainerInterface;
1616
use Symfony\Component\DependencyInjection\Definition;
17-
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18-
use Symfony\Component\DependencyInjection\ExpressionLanguage;
1917
use Symfony\Component\DependencyInjection\Reference;
2018
use Symfony\Component\DependencyInjection\ContainerBuilder;
2119
use Symfony\Component\ExpressionLanguage\Expression;
@@ -28,29 +26,33 @@
2826
* retrieve the graph in other passes from the compiler.
2927
*
3028
* @author Johannes M. Schmitt <[email protected]>
29+
* @author Nicolas Grekas <[email protected]>
3130
*/
3231
class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface
3332
{
3433
private $graph;
3534
private $currentDefinition;
3635
private $onlyConstructorArguments;
3736
private $lazy;
38-
private $expressionLanguage;
37+
private $inExpression;
38+
private $definitions;
39+
private $aliases;
3940

4041
/**
4142
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
4243
*/
4344
public function __construct(bool $onlyConstructorArguments = false)
4445
{
4546
$this->onlyConstructorArguments = $onlyConstructorArguments;
47+
$this->enableExpressionProcessing();
4648
}
4749

4850
/**
4951
* {@inheritdoc}
5052
*/
5153
public function setRepeatedPass(RepeatedPass $repeatedPass)
5254
{
53-
// no-op for BC
55+
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
5456
}
5557

5658
/**
@@ -62,13 +64,19 @@ public function process(ContainerBuilder $container)
6264
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
6365
$this->graph->clear();
6466
$this->lazy = false;
67+
$this->definitions = $container->getDefinitions();
68+
$this->aliases = $container->getAliases();
6569

66-
foreach ($container->getAliases() as $id => $alias) {
70+
foreach ($this->aliases as $id => $alias) {
6771
$targetId = $this->getDefinitionId((string) $alias);
68-
$this->graph->connect($id, $alias, $targetId, $this->getDefinition($targetId), null);
72+
$this->graph->connect($id, $alias, $targetId, null !== $targetId ? $this->container->getDefinition($targetId) : null, null);
6973
}
7074

71-
parent::process($container);
75+
try {
76+
parent::process($container);
77+
} finally {
78+
$this->aliases = $this->definitions = array();
79+
}
7280
}
7381

7482
protected function processValue($value, $isRoot = false)
@@ -83,13 +91,16 @@ protected function processValue($value, $isRoot = false)
8391
return $value;
8492
}
8593
if ($value instanceof Expression) {
86-
$this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
87-
88-
return $value;
94+
$this->inExpression = true;
95+
try {
96+
return parent::processValue($value);
97+
} finally {
98+
$this->inExpression = false;
99+
}
89100
}
90101
if ($value instanceof Reference) {
91102
$targetId = $this->getDefinitionId((string) $value);
92-
$targetDefinition = $this->getDefinition($targetId);
103+
$targetDefinition = null !== $targetId ? $this->container->getDefinition($targetId) : null;
93104

94105
$this->graph->connect(
95106
$this->currentId,
@@ -101,6 +112,19 @@ protected function processValue($value, $isRoot = false)
101112
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
102113
);
103114

115+
if ($this->inExpression) {
116+
$this->inExpression = false;
117+
$this->graph->connect(
118+
'.internal.reference_in_expression',
119+
null,
120+
$targetId,
121+
$targetDefinition,
122+
$value,
123+
$this->lazy || ($targetDefinition && $targetDefinition->isLazy()),
124+
true
125+
);
126+
}
127+
104128
return $value;
105129
}
106130
if (!$value instanceof Definition) {
@@ -127,49 +151,12 @@ protected function processValue($value, $isRoot = false)
127151
return $value;
128152
}
129153

130-
private function getDefinition(?string $id): ?Definition
131-
{
132-
return null === $id ? null : $this->container->getDefinition($id);
133-
}
134-
135154
private function getDefinitionId(string $id): ?string
136155
{
137-
while ($this->container->hasAlias($id)) {
138-
$id = (string) $this->container->getAlias($id);
139-
}
140-
141-
if (!$this->container->hasDefinition($id)) {
142-
return null;
143-
}
144-
145-
return $id;
146-
}
147-
148-
private function getExpressionLanguage()
149-
{
150-
if (null === $this->expressionLanguage) {
151-
if (!class_exists(ExpressionLanguage::class)) {
152-
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
153-
}
154-
155-
$providers = $this->container->getExpressionLanguageProviders();
156-
$this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
157-
if ('""' === substr_replace($arg, '', 1, -1)) {
158-
$id = stripcslashes(substr($arg, 1, -1));
159-
$id = $this->getDefinitionId($id);
160-
161-
$this->graph->connect(
162-
$this->currentId,
163-
$this->currentDefinition,
164-
$id,
165-
$this->getDefinition($id)
166-
);
167-
}
168-
169-
return sprintf('$this->get(%s)', $arg);
170-
});
156+
while (isset($this->aliases[$id])) {
157+
$id = (string) $this->aliases[$id];
171158
}
172159

173-
return $this->expressionLanguage;
160+
return isset($this->definitions[$id]) ? $id : null;
174161
}
175162
}

0 commit comments

Comments
 (0)