Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit eb2a152

Browse filesBrowse files
[DI] Fix deep-inlining of non-shared refs
1 parent c9f72e2 commit eb2a152
Copy full SHA for eb2a152

File tree

2 files changed

+90
-8
lines changed
Filter options

2 files changed

+90
-8
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+36-8Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1515
use Symfony\Component\DependencyInjection\Definition;
16+
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1617
use Symfony\Component\DependencyInjection\Reference;
1718

1819
/**
@@ -23,6 +24,7 @@
2324
class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface
2425
{
2526
private $repeatedPass;
27+
private $cloningIds = array();
2628
private $inlinedServiceIds = array();
2729

2830
/**
@@ -54,18 +56,44 @@ protected function processValue($value, $isRoot = false)
5456
// Reference found in ArgumentInterface::getValues() are not inlineable
5557
return $value;
5658
}
57-
if ($value instanceof Reference && $this->container->hasDefinition($id = (string) $value)) {
58-
$definition = $this->container->getDefinition($id);
5959

60-
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
61-
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
62-
$this->inlinedServiceIds[$id][] = $this->currentId;
63-
64-
return $definition->isShared() ? $definition : clone $definition;
60+
if ($value instanceof Definition && $this->cloningIds) {
61+
if ($value->isShared()) {
62+
return $value;
6563
}
64+
$value = clone $value;
65+
}
66+
67+
if (!$value instanceof Reference || !$this->container->hasDefinition($id = (string) $value)) {
68+
return parent::processValue($value, $isRoot);
69+
}
70+
71+
$definition = $this->container->getDefinition($id);
72+
73+
if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
74+
return $value;
6675
}
6776

68-
return parent::processValue($value, $isRoot);
77+
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
78+
$this->inlinedServiceIds[$id][] = $this->currentId;
79+
80+
if ($definition->isShared()) {
81+
return $definition;
82+
}
83+
84+
if (isset($this->cloningIds[$id])) {
85+
$ids = array_keys($this->cloningIds);
86+
$ids[] = $id;
87+
88+
throw new ServiceCircularReferenceException($id, array_slice($ids, array_search($id, $ids)));
89+
}
90+
91+
$this->cloningIds[$id] = true;
92+
try {
93+
return $this->processValue($definition);
94+
} finally {
95+
unset($this->cloningIds[$id]);
96+
}
6997
}
7098

7199
/**

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/InlineServiceDefinitionsPassTest.php
+54Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,60 @@ public function testProcessInlinesMixedServicesLoop()
111111
$this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
112112
}
113113

114+
/**
115+
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
116+
* @expectedExceptionMessage Circular reference detected for service "bar", path: "bar -> foo -> bar".
117+
*/
118+
public function testProcessThrowsOnNonSharedLoops()
119+
{
120+
$container = new ContainerBuilder();
121+
$container
122+
->register('foo')
123+
->addArgument(new Reference('bar'))
124+
->setShared(false)
125+
;
126+
$container
127+
->register('bar')
128+
->setShared(false)
129+
->addMethodCall('setFoo', array(new Reference('foo')))
130+
;
131+
132+
$this->process($container);
133+
}
134+
135+
public function testProcessNestedNonSharedServices()
136+
{
137+
$container = new ContainerBuilder();
138+
$container
139+
->register('foo')
140+
->addArgument(new Reference('bar1'))
141+
->addArgument(new Reference('bar2'))
142+
;
143+
$container
144+
->register('bar1')
145+
->setShared(false)
146+
->addArgument(new Reference('baz'))
147+
;
148+
$container
149+
->register('bar2')
150+
->setShared(false)
151+
->addArgument(new Reference('baz'))
152+
;
153+
$container
154+
->register('baz')
155+
->setShared(false)
156+
;
157+
158+
$this->process($container);
159+
160+
$baz1 = $container->getDefinition('foo')->getArgument(0)->getArgument(0);
161+
$baz2 = $container->getDefinition('foo')->getArgument(1)->getArgument(0);
162+
163+
$this->assertEquals($container->getDefinition('baz'), $baz1);
164+
$this->assertEquals($container->getDefinition('baz'), $baz2);
165+
$this->assertNotSame($baz1, $baz2);
166+
}
167+
114168
public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition()
115169
{
116170
$container = new ContainerBuilder();

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.