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 528ff30

Browse filesBrowse files
[DependencyInjection] Fix deduplicating service instances in circular graphs
1 parent e7ec8a6 commit 528ff30
Copy full SHA for 528ff30

File tree

3 files changed

+51
-20
lines changed
Filter options

3 files changed

+51
-20
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+14-12Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
3333
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
3434
use Symfony\Component\DependencyInjection\ExpressionLanguage;
35-
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
35+
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;
3636
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
3737
use Symfony\Component\DependencyInjection\Loader\FileLoader;
3838
use Symfony\Component\DependencyInjection\Parameter;
@@ -95,9 +95,10 @@ class PhpDumper extends Dumper
9595
private $baseClass;
9696

9797
/**
98-
* @var ProxyDumper
98+
* @var DumperInterface
9999
*/
100100
private $proxyDumper;
101+
private $hasProxyDumper = false;
101102

102103
/**
103104
* {@inheritdoc}
@@ -114,9 +115,10 @@ public function __construct(ContainerBuilder $container)
114115
/**
115116
* Sets the dumper to be used when dumping proxies in the generated container.
116117
*/
117-
public function setProxyDumper(ProxyDumper $proxyDumper)
118+
public function setProxyDumper(DumperInterface $proxyDumper)
118119
{
119120
$this->proxyDumper = $proxyDumper;
121+
$this->hasProxyDumper = !$proxyDumper instanceof NullDumper;
120122
}
121123

122124
/**
@@ -174,7 +176,7 @@ public function dump(array $options = [])
174176

175177
$this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
176178

177-
if ($this->getProxyDumper() instanceof NullDumper) {
179+
if (!$this->hasProxyDumper) {
178180
(new AnalyzeServiceReferencesPass(true, false))->process($this->container);
179181
try {
180182
(new CheckCircularReferencesPass())->process($this->container);
@@ -407,7 +409,7 @@ class %s extends {$options['class']}
407409
/**
408410
* Retrieves the currently set proxy dumper or instantiates one.
409411
*/
410-
private function getProxyDumper(): ProxyDumper
412+
private function getProxyDumper(): DumperInterface
411413
{
412414
if (!$this->proxyDumper) {
413415
$this->proxyDumper = new NullDumper();
@@ -418,7 +420,7 @@ private function getProxyDumper(): ProxyDumper
418420

419421
private function analyzeReferences()
420422
{
421-
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
423+
(new AnalyzeServiceReferencesPass(false, $this->hasProxyDumper))->process($this->container);
422424
$checkedNodes = [];
423425
$this->circularReferences = [];
424426
$this->singleUsePrivateIds = [];
@@ -445,13 +447,13 @@ private function collectCircularReferences(string $sourceId, array $edges, array
445447
foreach ($edges as $edge) {
446448
$node = $edge->getDestNode();
447449
$id = $node->getId();
448-
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isLazy() || $edge->isWeak()) {
450+
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isWeak()) {
449451
continue;
450452
}
451453

452454
if (isset($path[$id])) {
453455
$loop = null;
454-
$loopByConstructor = $edge->isReferencedByConstructor();
456+
$loopByConstructor = $edge->isReferencedByConstructor() && !$edge->isLazy();
455457
$pathInLoop = [$id, []];
456458
foreach ($path as $k => $pathByConstructor) {
457459
if (null !== $loop) {
@@ -465,7 +467,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
465467
}
466468
$this->addCircularReferences($id, $loop, $loopByConstructor);
467469
} elseif (!isset($checkedNodes[$id])) {
468-
$this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $loops, $path, $edge->isReferencedByConstructor());
470+
$this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $loops, $path, $edge->isReferencedByConstructor() && !$edge->isLazy());
469471
} elseif (isset($loops[$id])) {
470472
// we already had detected loops for this edge
471473
// let's check if we have a common ancestor in one of the detected loops
@@ -486,7 +488,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
486488

487489
// we can now build the loop
488490
$loop = null;
489-
$loopByConstructor = $edge->isReferencedByConstructor();
491+
$loopByConstructor = $edge->isReferencedByConstructor() && !$edge->isLazy();
490492
foreach ($fillPath as $k => $pathByConstructor) {
491493
if (null !== $loop) {
492494
$loop[] = $k;
@@ -988,7 +990,7 @@ private function addInlineReference(string $id, Definition $definition, string $
988990
return '';
989991
}
990992

991-
$hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);
993+
$hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]) && !($this->hasProxyDumper && $definition->isLazy());
992994

993995
if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {
994996
$code = $this->addInlineService($id, $definition, $definition);
@@ -1031,7 +1033,7 @@ private function addInlineService(string $id, Definition $definition, Definition
10311033

10321034
if ($isSimpleInstance = $isRootInstance = null === $inlineDef) {
10331035
foreach ($this->serviceCalls as $targetId => [$callCount, $behavior, $byConstructor]) {
1034-
if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId]) {
1036+
if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId] && !($this->hasProxyDumper && $definition->isLazy())) {
10351037
$code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor);
10361038
}
10371039
}

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,13 @@ protected function getBar6Service()
491491
*/
492492
protected function getDoctrine_ListenerService()
493493
{
494-
return $this->privates['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
494+
$a = ($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService());
495+
496+
if (isset($this->privates['doctrine.listener'])) {
497+
return $this->privates['doctrine.listener'];
498+
}
499+
500+
return $this->privates['doctrine.listener'] = new \stdClass($a);
495501
}
496502

497503
/**

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
+30-7Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,16 @@ protected function getDoctrine_EntityListenerResolverService()
285285
*/
286286
protected function getDoctrine_EntityManagerService()
287287
{
288-
$a = new \stdClass();
289-
$a->resolver = ($this->services['doctrine.entity_listener_resolver'] ?? $this->getDoctrine_EntityListenerResolverService());
290-
$a->flag = 'ok';
288+
$a = ($this->services['doctrine.entity_listener_resolver'] ?? $this->getDoctrine_EntityListenerResolverService());
289+
290+
if (isset($this->services['doctrine.entity_manager'])) {
291+
return $this->services['doctrine.entity_manager'];
292+
}
293+
$b = new \stdClass();
294+
$b->resolver = $a;
295+
$b->flag = 'ok';
291296

292-
return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($a);
297+
return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($b);
293298
}
294299

295300
/**
@@ -299,7 +304,13 @@ protected function getDoctrine_EntityManagerService()
299304
*/
300305
protected function getDoctrine_ListenerService()
301306
{
302-
return $this->services['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
307+
$a = ($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService());
308+
309+
if (isset($this->services['doctrine.listener'])) {
310+
return $this->services['doctrine.listener'];
311+
}
312+
313+
return $this->services['doctrine.listener'] = new \stdClass($a);
303314
}
304315

305316
/**
@@ -495,7 +506,13 @@ protected function getLoggerService()
495506
*/
496507
protected function getMailer_TransportService()
497508
{
498-
return $this->services['mailer.transport'] = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService())->create();
509+
$a = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService());
510+
511+
if (isset($this->services['mailer.transport'])) {
512+
return $this->services['mailer.transport'];
513+
}
514+
515+
return $this->services['mailer.transport'] = $a->create();
499516
}
500517

501518
/**
@@ -518,7 +535,13 @@ protected function getMailer_TransportFactoryService()
518535
*/
519536
protected function getMailer_TransportFactory_AmazonService()
520537
{
521-
return $this->services['mailer.transport_factory.amazon'] = new \stdClass(($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service()));
538+
$a = ($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service());
539+
540+
if (isset($this->services['mailer.transport_factory.amazon'])) {
541+
return $this->services['mailer.transport_factory.amazon'];
542+
}
543+
544+
return $this->services['mailer.transport_factory.amazon'] = new \stdClass($a);
522545
}
523546

524547
/**

0 commit comments

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