Skip to content

Commit 380cb10

Browse files
[DI] fix inlining of non-shared services
1 parent ae37887 commit 380cb10

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
3030
private $connectedIds = [];
3131
private $notInlinedIds = [];
3232
private $inlinedIds = [];
33+
private $notInlinableIds = [];
3334
private $graph;
3435

3536
public function __construct(AnalyzeServiceReferencesPass $analyzingPass = null)
@@ -99,6 +100,10 @@ public function process(ContainerBuilder $container)
99100
}
100101

101102
foreach ($remainingInlinedIds as $id) {
103+
if (isset($this->notInlinableIds[$id])) {
104+
continue;
105+
}
106+
102107
$definition = $container->getDefinition($id);
103108

104109
if (!$definition->isShared() && !$definition->isPublic()) {
@@ -108,6 +113,7 @@ public function process(ContainerBuilder $container)
108113
} finally {
109114
$this->container = null;
110115
$this->connectedIds = $this->notInlinedIds = $this->inlinedIds = [];
116+
$this->notInlinableIds = [];
111117
$this->graph = null;
112118
}
113119
}
@@ -138,6 +144,8 @@ protected function processValue($value, $isRoot = false)
138144
$definition = $this->container->getDefinition($id);
139145

140146
if (!$this->isInlineableDefinition($id, $definition)) {
147+
$this->notInlinableIds[$id] = true;
148+
141149
return $value;
142150
}
143151

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,10 @@ private function addInlineReference(string $id, Definition $definition, string $
885885
return '';
886886
}
887887

888+
if ($this->container->hasDefinition($targetId) && ($def = $this->container->getDefinition($targetId)) && !$def->isShared()) {
889+
return '';
890+
}
891+
888892
$hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);
889893

890894
if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
2020
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
2121
use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator;
22+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
2223
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
2324
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
2425
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -714,6 +715,24 @@ public function testNonSharedLazyDefinitionReferences()
714715
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_non_shared_lazy.php', $dumper->dump());
715716
}
716717

718+
public function testNonSharedDuplicates()
719+
{
720+
$container = new ContainerBuilder();
721+
$container->register('foo', 'stdClass')->setShared(false);
722+
$container->register('baz', 'stdClass')->setPublic(true)
723+
->addArgument(new ServiceLocatorArgument(['foo' => new Reference('foo')]));
724+
$container->register('bar', 'stdClass')->setPublic(true)
725+
->addArgument(new Reference('foo'))
726+
->addArgument(new Reference('foo'))
727+
;
728+
$container->compile();
729+
730+
$dumper = new PhpDumper($container);
731+
$dumper->setProxyDumper(new \DummyProxyDumper());
732+
733+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_non_shared_duplicates.php', $dumper->dump());
734+
}
735+
717736
public function testInitializePropertiesBeforeMethodCalls()
718737
{
719738
require_once self::$fixturesPath.'/includes/classes.php';
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
4+
use Symfony\Component\DependencyInjection\ContainerInterface;
5+
use Symfony\Component\DependencyInjection\Container;
6+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
7+
use Symfony\Component\DependencyInjection\Exception\LogicException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
11+
12+
/**
13+
* This class has been auto-generated
14+
* by the Symfony Dependency Injection Component.
15+
*
16+
* @final
17+
*/
18+
class ProjectServiceContainer extends Container
19+
{
20+
private $parameters = [];
21+
private $getService;
22+
23+
public function __construct()
24+
{
25+
$this->getService = \Closure::fromCallable([$this, 'getService']);
26+
$this->services = $this->privates = [];
27+
$this->methodMap = [
28+
'bar' => 'getBarService',
29+
'baz' => 'getBazService',
30+
];
31+
32+
$this->aliases = [];
33+
}
34+
35+
public function compile(): void
36+
{
37+
throw new LogicException('You cannot compile a dumped container that was already compiled.');
38+
}
39+
40+
public function isCompiled(): bool
41+
{
42+
return true;
43+
}
44+
45+
public function getRemovedIds(): array
46+
{
47+
return [
48+
'.service_locator.BHJD0.a' => true,
49+
'Psr\\Container\\ContainerInterface' => true,
50+
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
51+
'foo' => true,
52+
];
53+
}
54+
55+
/**
56+
* Gets the public 'bar' shared service.
57+
*
58+
* @return \stdClass
59+
*/
60+
protected function getBarService()
61+
{
62+
return $this->services['bar'] = new \stdClass((new \stdClass()), (new \stdClass()));
63+
}
64+
65+
/**
66+
* Gets the public 'baz' shared service.
67+
*
68+
* @return \stdClass
69+
*/
70+
protected function getBazService()
71+
{
72+
return $this->services['baz'] = new \stdClass(new \Symfony\Component\DependencyInjection\Argument\ServiceLocator($this->getService, [
73+
'foo' => [false, 'foo', 'getFooService', false],
74+
], [
75+
'foo' => '?',
76+
]));
77+
}
78+
79+
/**
80+
* Gets the private 'foo' service.
81+
*
82+
* @return \stdClass
83+
*/
84+
protected function getFooService()
85+
{
86+
return new \stdClass();
87+
}
88+
}

0 commit comments

Comments
 (0)