Skip to content

Commit 393c603

Browse files
bug #49128 [DependencyInjection] Fix combinatory explosion when autowiring union and intersection types (nicolas-grekas)
This PR was merged into the 5.4 branch. Discussion ---------- [DependencyInjection] Fix combinatory explosion when autowiring union and intersection types | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #49105 | License | MIT | Doc PR | - The performance is so bad in the reported situation that this is a bugfix. Commits ------- 8b67567 [DependencyInjection] Fix combinatory explosion when autowiring union and intersection types
2 parents 89d7780 + 8b67567 commit 393c603

File tree

1 file changed

+23
-40
lines changed

1 file changed

+23
-40
lines changed

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

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class AutowirePass extends AbstractRecursivePass
4545
private $decoratedMethodIndex;
4646
private $decoratedMethodArgumentIndex;
4747
private $typesClone;
48-
private $combinedAliases;
4948

5049
public function __construct(bool $throwOnAutowireException = true)
5150
{
@@ -61,8 +60,6 @@ public function __construct(bool $throwOnAutowireException = true)
6160
*/
6261
public function process(ContainerBuilder $container)
6362
{
64-
$this->populateCombinedAliases($container);
65-
6663
try {
6764
$this->typesClone = clone $this;
6865
parent::process($container);
@@ -75,7 +72,6 @@ public function process(ContainerBuilder $container)
7572
$this->decoratedMethodIndex = null;
7673
$this->decoratedMethodArgumentIndex = null;
7774
$this->typesClone = null;
78-
$this->combinedAliases = [];
7975
}
8076
}
8177

@@ -375,12 +371,12 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
375371
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
376372
}
377373

378-
if (null !== ($alias = $this->combinedAliases[$alias] ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
374+
if (null !== ($alias = $this->getCombinedAlias($type, $name) ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
379375
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
380376
}
381377

382378
if ($this->container->has($name) && !$this->container->findDefinition($name)->isAbstract()) {
383-
foreach ($this->container->getAliases() + $this->combinedAliases as $id => $alias) {
379+
foreach ($this->container->getAliases() as $id => $alias) {
384380
if ($name === (string) $alias && str_starts_with($id, $type.' $')) {
385381
return new TypedReference($name, $type, $reference->getInvalidBehavior());
386382
}
@@ -392,7 +388,7 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
392388
return new TypedReference($type, $type, $reference->getInvalidBehavior());
393389
}
394390

395-
if (null !== ($alias = $this->combinedAliases[$type] ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
391+
if (null !== ($alias = $this->getCombinedAlias($type) ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
396392
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
397393
}
398394

@@ -586,44 +582,31 @@ private function populateAutowiringAlias(string $id): void
586582
}
587583
}
588584

589-
private function populateCombinedAliases(ContainerBuilder $container): void
585+
private function getCombinedAlias(string $type, string $name = null): ?string
590586
{
591-
$this->combinedAliases = [];
592-
$reverseAliases = [];
593-
594-
foreach ($container->getAliases() as $id => $alias) {
595-
if (!preg_match('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))^((?&V)(?:\\\\(?&V))*+)(?: \$((?&V)))?$/', $id, $m)) {
596-
continue;
597-
}
598-
599-
$type = $m[2];
600-
$name = $m[3] ?? '';
601-
$reverseAliases[(string) $alias][$name][] = $type;
587+
if (str_contains($type, '&')) {
588+
$types = explode('&', $type);
589+
} elseif (str_contains($type, '|')) {
590+
$types = explode('|', $type);
591+
} else {
592+
return null;
602593
}
603594

604-
foreach ($reverseAliases as $alias => $names) {
605-
foreach ($names as $name => $types) {
606-
if (2 > $count = \count($types)) {
607-
continue;
608-
}
609-
sort($types);
610-
$i = 1 << $count;
611-
612-
// compute the powerset of the list of types
613-
while ($i--) {
614-
$set = [];
615-
for ($j = 0; $j < $count; ++$j) {
616-
if ($i & (1 << $j)) {
617-
$set[] = $types[$j];
618-
}
619-
}
595+
$alias = null;
596+
$suffix = $name ? ' $'.$name : '';
620597

621-
if (2 <= \count($set)) {
622-
$this->combinedAliases[implode('&', $set).('' === $name ? '' : ' $'.$name)] = $alias;
623-
$this->combinedAliases[implode('|', $set).('' === $name ? '' : ' $'.$name)] = $alias;
624-
}
625-
}
598+
foreach ($types as $type) {
599+
if (!$this->container->hasAlias($type.$suffix)) {
600+
return null;
601+
}
602+
603+
if (null === $alias) {
604+
$alias = (string) $this->container->getAlias($type.$suffix);
605+
} elseif ((string) $this->container->getAlias($type.$suffix) !== $alias) {
606+
return null;
626607
}
627608
}
609+
610+
return $alias;
628611
}
629612
}

0 commit comments

Comments
 (0)