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

Skip to content

Commit 9945d8a

Browse files
committed
bug #18265 Optimize ReplaceAliasByActualDefinitionPass (ajb-in)
This PR was merged into the 2.3 branch. Discussion ---------- Optimize ReplaceAliasByActualDefinitionPass | Q | A | ------------- | --- | Branch? | 2.3 | Bug fix? | yes (performance) | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Previous implementation passed over every definition for every alias (n*m runtime). New implementation passes once over all aliases and once over all definitions (n+m). Also removing needless "restart" logic. Commits ------- ab8dc0c Optimize ReplaceAliasByActualDefinitionPass
2 parents f1a87db + ab8dc0c commit 9945d8a

File tree

1 file changed

+61
-68
lines changed

1 file changed

+61
-68
lines changed

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

Lines changed: 61 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
2525
{
2626
private $compiler;
2727
private $formatter;
28-
private $sourceId;
2928

3029
/**
3130
* Process the Container to replace aliases with service definitions.
@@ -36,105 +35,99 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
3635
*/
3736
public function process(ContainerBuilder $container)
3837
{
38+
// Setup
3939
$this->compiler = $container->getCompiler();
4040
$this->formatter = $this->compiler->getLoggingFormatter();
41-
42-
foreach ($container->getAliases() as $id => $alias) {
43-
$aliasId = (string) $alias;
44-
45-
if ('service_container' === $aliasId) {
41+
// First collect all alias targets that need to be replaced
42+
$seenAliasTargets = array();
43+
$replacements = array();
44+
foreach ($container->getAliases() as $definitionId => $target) {
45+
$targetId = (string) $target;
46+
// Special case: leave this target alone
47+
if ('service_container' === $targetId) {
4648
continue;
4749
}
48-
50+
// Check if target needs to be replaces
51+
if (isset($replacements[$targetId])) {
52+
$container->setAlias($definitionId, $replacements[$targetId]);
53+
}
54+
// No neeed to process the same target twice
55+
if (isset($seenAliasTargets[$targetId])) {
56+
continue;
57+
}
58+
// Process new target
59+
$seenAliasTargets[$targetId] = true;
4960
try {
50-
$definition = $container->getDefinition($aliasId);
61+
$definition = $container->getDefinition($targetId);
5162
} catch (InvalidArgumentException $e) {
52-
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e);
63+
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e);
5364
}
54-
5565
if ($definition->isPublic()) {
5666
continue;
5767
}
58-
68+
// Remove private definition and schedule for replacement
5969
$definition->setPublic(true);
60-
$container->setDefinition($id, $definition);
61-
$container->removeDefinition($aliasId);
62-
63-
$this->updateReferences($container, $aliasId, $id);
64-
65-
// we have to restart the process due to concurrent modification of
66-
// the container
67-
$this->process($container);
68-
69-
break;
70+
$container->setDefinition($definitionId, $definition);
71+
$container->removeDefinition($targetId);
72+
$replacements[$targetId] = $definitionId;
7073
}
71-
}
72-
73-
/**
74-
* Updates references to remove aliases.
75-
*
76-
* @param ContainerBuilder $container The container
77-
* @param string $currentId The alias identifier being replaced
78-
* @param string $newId The id of the service the alias points to
79-
*/
80-
private function updateReferences($container, $currentId, $newId)
81-
{
82-
foreach ($container->getAliases() as $id => $alias) {
83-
if ($currentId === (string) $alias) {
84-
$container->setAlias($id, $newId);
85-
}
86-
}
87-
88-
foreach ($container->getDefinitions() as $id => $definition) {
89-
$this->sourceId = $id;
90-
91-
$definition->setArguments(
92-
$this->updateArgumentReferences($definition->getArguments(), $currentId, $newId)
93-
);
94-
95-
$definition->setMethodCalls(
96-
$this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId)
97-
);
98-
99-
$definition->setProperties(
100-
$this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
101-
);
102-
103-
$definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(), $currentId, $newId));
74+
// Now replace target instances in all definitions
75+
foreach ($container->getDefinitions() as $definitionId => $definition) {
76+
$definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments()));
77+
$definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls()));
78+
$definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties()));
79+
$definition->setFactoryService($this->updateFactoryReferenceId($replacements, $definition->getFactoryService()));
10480
}
10581
}
10682

10783
/**
108-
* Updates argument references.
84+
* Recursively updates references in an array.
10985
*
110-
* @param array $arguments An array of Arguments
111-
* @param string $currentId The alias identifier
112-
* @param string $newId The identifier the alias points to
86+
* @param array $replacements Table of aliases to replace
87+
* @param string $definitionId Identifier of this definition
88+
* @param array $arguments Where to replace the aliases
11389
*
11490
* @return array
11591
*/
116-
private function updateArgumentReferences(array $arguments, $currentId, $newId)
92+
private function updateArgumentReferences(array $replacements, $definitionId, array $arguments)
11793
{
11894
foreach ($arguments as $k => $argument) {
95+
// Handle recursion step
11996
if (is_array($argument)) {
120-
$arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId);
121-
} elseif ($argument instanceof Reference) {
122-
if ($currentId === (string) $argument) {
123-
$arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
124-
$this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId));
125-
}
97+
$arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument);
98+
continue;
12699
}
100+
// Skip arguments that don't need replacement
101+
if (!$argument instanceof Reference) {
102+
continue;
103+
}
104+
$referenceId = (string) $argument;
105+
if (!isset($replacements[$referenceId])) {
106+
continue;
107+
}
108+
// Perform the replacement
109+
$newId = $replacements[$referenceId];
110+
$arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
111+
$this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $definitionId, $referenceId, $newId));
127112
}
128113

129114
return $arguments;
130115
}
131116

132-
private function updateFactoryServiceReference($factoryService, $currentId, $newId)
117+
/**
118+
* Returns the updated reference for the factory service.
119+
*
120+
* @param array $replacements Table of aliases to replace
121+
* @param string|null $referenceId Factory service reference identifier
122+
*
123+
* @return string|null
124+
*/
125+
private function updateFactoryReferenceId(array $replacements, $referenceId)
133126
{
134-
if (null === $factoryService) {
127+
if (null === $referenceId) {
135128
return;
136129
}
137130

138-
return $currentId === $factoryService ? $newId : $factoryService;
131+
return isset($replacements[$referenceId]) ? $replacements[$referenceId] : $referenceId;
139132
}
140133
}

0 commit comments

Comments
 (0)