8000 [DI] Improve performance of removing/inlining passes · symfony/symfony@cf375e5 · GitHub
[go: up one dir, main page]

Skip to content

Commit cf375e5

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

14 files changed

+239
-128
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: 38 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 <p@tchwork.com>
@@ -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,11 +47,17 @@ 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
*
4858
* @param mixed $value
4959
* @param bool $isRoot
60+
* @param bool $inExpression
5061
*
5162
* @return mixed The processed value
5263
*/
@@ -63,6 +74,8 @@ protected function processValue($value, $isRoot = false)
6374
}
6475
} elseif ($value instanceof ArgumentInterface) {
6576
$value->setValues($this->processValue($value->getValues()));
77+
} elseif ($value instanceof Expression && $this->processExpressions) {
78+
$this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
6679
} elseif ($value instanceof Definition) {
6780
$value->setArguments($this->processValue($value->getArguments()));
6881
$value->setProperties($this->processValue($value->getProperties()));
@@ -169,4 +182,29 @@ protected function getReflectionMethod(Definition $definition, $method)
169182

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

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

Lines changed: 31 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@
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;
21-
use Symfony\Component\ExpressionLanguage\Expression;
2219

2320
/**
2421
* Run this pass before passes that need to know more about the relation of
@@ -28,29 +25,32 @@
2825
* retrieve the graph in other passes from the compiler.
2926
*
3027
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
28+
* @author Nicolas Grekas <p@tchwork.com>
3129
*/
3230
class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface
3331
{
3432
private $graph;
3533
private $currentDefinition;
3634
private $onlyConstructorArguments;
3735
private $lazy;
38-
private $expressionLanguage;
36+
private $definitions;
37+
private $aliases;
3938

4039
/**
4140
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
4241
*/
4342
public function __construct(bool $onlyConstructorArguments = false)
4443
{
4544
$this->onlyConstructorArguments = $onlyConstructorArguments;
45+
$this->enableExpressionProcessing();
4646
}
4747

4848
/**
4949
* {@inheritdoc}
5050
*/
5151
public function setRepeatedPass(RepeatedPass $repeatedPass)
5252
{
53-
// no-op for BC
53+
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
5454
}
5555

5656
/**
@@ -62,16 +62,22 @@ public function process(ContainerBuilder $container)
6262
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
6363
$this->graph->clear();
6464
$this->lazy = false;
65+
$this->definitions = $container->getDefinitions();
66+
$this->aliases = $container->getAliases();
6567

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

71-
parent::process($container);
73+
try {
74+
parent::process($container);
75+
} finally {
76+
$this->aliases = $this->definitions = array();
77+
}
7278
}
7379

74-
protected function processValue($value, $isRoot = false)
80+
protected function processValue($value, $isRoot = false, bool $inExpression = false)
7581
{
7682
$lazy = $this->lazy;
7783

@@ -82,14 +88,9 @@ protected function processValue($value, $isRoot = false)
8288

8389
return $value;
8490
}
85-
if ($value instanceof Expression) {
86-
$this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
87-
88-
return $value;
89-
}
9091
if ($value instanceof Reference) {
9192
$targetId = $this->getDefinitionId((string) $value);
92-
$targetDefinition = $this->getDefinition($targetId);
93+
$targetDefinition = null !== $targetId ? $this->container->getDefinition($targetId) : null;
9394

9495
$this->graph->connect(
9596
$this->currentId,
@@ -101,6 +102,18 @@ protected function processValue($value, $isRoot = false)
101102
ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
102103
);
103104

105+
if ($inExpression) {
106+
$this->graph->connect(
107+
'.internal.reference_in_expression',
108+
null,
109+
$targetId,
110+
$targetDefinition,
111+
$value,
112+
$this->lazy || ($targetDefinition && $targetDefinition->isLazy()),
113+
true
114+
);
115+
}
116+
104117
return $value;
105118
}
106119
if (!$value instanceof Definition) {
@@ -127,49 +140,12 @@ protected function processValue($value, $isRoot = false)
127140
return $value;
128141
}
129142

130-
private function getDefinition(?string $id): ?Definition
131-
{
132-
return null === $id ? null : $this->container->getDefinition($id);
133-
}
134-
135143
private function getDefinitionId(string $id): ?string
136144
{
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-
});
145+
while (isset($this->aliases[$id])) {
146+
$id = (string) $this->aliases[$id];
171147
}
172148

173-
return $this->expressionLanguage;
149+
return isset($this->definitions[$id]) ? $id : null;
174150
}
175151
}

0 commit comments

Comments
 (0)
0