8000 Merge branch '4.0' · symfony/symfony@7bab5b2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7bab5b2

Browse files
Merge branch '4.0'
* 4.0: [DI] Fix circular reference when using setters [DI] Clear service reference graph
2 parents ed2222b + ff87b4c commit 7bab5b2

14 files changed

+425
-257
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ public function compile(ContainerBuilder $container)
113113
}
114114

115115
throw $e;
116+
} finally {
117+
$this->getServiceReferenceGraph()->clear();
116118
}
117119
}
118120
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public function getNodes(): array
6464
*/
6565
public function clear()
6666
{
67+
foreach ($this->nodes as $node) {
68+
$node->clear();
69+
}
6770
$this->nodes = array();
6871
}
6972

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,12 @@ public function getValue()
107107
{
108108
return $this->value;
109109
}
110+
111+
/**
112+
* Clears all edges.
113+
*/
114+
public function clear()
115+
{
116+
$this->inEdges = $this->outEdges = array();
117+
}
110118
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,14 @@ public function has($id)
519519
*/
520520
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
521521
{
522+
return $this->doGet($id, $invalidBehavior);
523+
}
524+
525+
private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = array())
526+
{
527+
if (isset($inlineServices[$id])) {
528+
return $inlineServices[$id];
529+
}
522530
if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) {
523531
return parent::get($id, $invalidBehavior);
524532
}
@@ -527,7 +535,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV
527535
}
528536

529537
if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
530-
return $this->get((string) $this->aliasDefinitions[$id], $invalidBehavior);
538+
return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices);
531539
}
532540

533541
try {
@@ -544,7 +552,7 @@ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INV
544552
$this->{$loading}[$id] = true;
545553

546554
try {
547-
$service = $this->createService($definition, new \SplObjectStorage(), $id);
555+
$service = $this->createService($definition, $inlineServices, $id);
548556
} finally {
549557
unset($this->{$loading}[$id]);
550558
}
@@ -978,10 +986,10 @@ public function findDefinition($id)
978986
* @throws RuntimeException When the service is a synthetic service
979987
* @throws InvalidArgumentException When configure callable is not callable
980988
*/
981-
private function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true)
989+
private function createService(Definition $definition, array &$inlineServices, $id = null, $tryProxy = true)
982990
{
983-
if (null === $id && isset($inlinedDefinitions[$definition])) {
984-
return $inlinedDefinitions[$definition];
991+
if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) {
992+
return $inlineServices[$h];
985993
}
986994

987995
if ($definition instanceof ChildDefinition) {
@@ -1002,11 +1010,11 @@ private function createService(Definition $definition, \SplObjectStorage $inline
10021010
->instantiateProxy(
10031011
$this,
10041012
$definition,
1005-
$id, function () use ($definition, $inlinedDefinitions, $id) {
1006-
return $this->createService($definition, $inlinedDefinitions, $id, false);
1013+
$id, function () use ($definition, &$inlineServices, $id) {
1014+
return $this->createService($definition, $inlineServices, $id, false);
10071015
}
10081016
);
1009-
$this->shareService($definition, $proxy, $id, $inlinedDefinitions);
1017+
$this->shareService($definition, $proxy, $id, $inlineServices);
10101018

10111019
return $proxy;
10121020
}
@@ -1017,15 +1025,15 @@ private function createService(Definition $definition, \SplObjectStorage $inline
10171025
require_once $parameterBag->resolveValue($definition->getFile());
10181026
}
10191027

1020-
$arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions);
1028+
$arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices);
10211029

10221030
if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) {
10231031
return $this->services[$id];
10241032
}
10251033

10261034
if (null !== $factory = $definition->getFactory()) {
10271035
if (is_array($factory)) {
1028-
$factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]);
1036+
$factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices), $factory[1]);
10291037
} elseif (!is_string($factory)) {
10301038
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
10311039
}
@@ -1051,26 +1059,26 @@ private function createService(Definition $definition, \SplObjectStorage $inline
10511059

10521060
if ($tryProxy || !$definition->isLazy()) {
10531061
// share only if proxying failed, or if not a proxy
1054-
$this->shareService($definition, $service, $id, $inlinedDefinitions);
1062+
$this->shareService($definition, $service, $id, $inlineServices);
10551063
}
10561064

1057-
$properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions);
1065+
$properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlineServices);
10581066
foreach ($properties as $name => $value) {
10591067
$service->$name = $value;
10601068
}
10611069

10621070
foreach ($definition->getMethodCalls() as $call) {
1063-
$this->callMethod($service, $call, $inlinedDefinitions);
1071+
$this->callMethod($service, $call, $inlineServices);
10641072
}
10651073

10661074
if ($callable = $definition->getConfigurator()) {
10671075
if (is_array($callable)) {
10681076
$callable[0] = $parameterBag->resolveValue($callable[0]);
10691077

10701078
if ($callable[0] instanceof Reference) {
1071-
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
1079+
$callable[0] = $this->doGet((string) $callable[0], $callable[0]->getInvalidBehavior(), $inlineServices);
10721080
} elseif ($callable[0] instanceof Definition) {
1073-
$callable[0] = $this->createService($callable[0], $inlinedDefinitions);
1081+
$callable[0] = $this->createService($callable[0], $inlineServices);
10741082
}
10751083
}
10761084

@@ -1094,14 +1102,14 @@ private function createService(Definition $definition, \SplObjectStorage $inline
10941102
*/
10951103
public function resolveServices($value)
10961104
{
1097-
return $this->doResolveServices($value, new \SplObjectStorage());
1105+
return $this->doResolveServices($value);
10981106
}
10991107

1100-
private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions)
1108+
private function doResolveServices($value, array &$inlineServices = array())
11011109
{
11021110
if (is_array($value)) {
11031111
foreach ($value as $k => $v) {
1104-
$value[$k] = $this->doResolveServices($v, $inlinedDefinitions);
1112+
$value[$k] = $this->doResolveServices($v, $inlineServices);
11051113
}
11061114
} elseif ($value instanceof ServiceClosureArgument) {
11071115
$reference = $value->getValues()[0];
@@ -1117,7 +1125,7 @@ private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions
11171125
}
11181126
}
11191127
foreach (self::getInitializedConditionals($v) as $s) {
1120-
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1128+
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
11211129
continue 2;
11221130
}
11231131
}
@@ -1133,7 +1141,7 @@ private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions
11331141
}
11341142
}
11351143
foreach (self::getInitializedConditionals($v) as $s) {
1136-
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1144+
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
11371145
continue 2;
11381146
}
11391147
}
@@ -1144,9 +1152,9 @@ private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions
11441152
return $count;
11451153
});
11461154
} elseif ($value instanceof Reference) {
1147-
$value = $this->get((string) $value, $value->getInvalidBehavior());
1155+
$value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices);
11481156
} elseif ($value instanceof Definition) {
1149-
$value = $this->createService($value, $inlinedDefinitions);
1157+
$value = $this->createService($value, $inlineServices);
11501158
} elseif ($value instanceof Expression) {
11511159
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
11521160
}
@@ -1443,20 +1451,20 @@ private function getProxyInstantiator(): InstantiatorInterface
14431451
return $this->proxyInstantiator;
14441452
}
14451453

1446-
private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions)
1454+
private function callMethod($service, $call, array &$inlineServices)
14471455
{
14481456
foreach (self::getServiceConditionals($call[1]) as $s) {
14491457
if (!$this->has($s)) {
14501458
return;
14511459
}
14521460
}
14531461
foreach (self::getInitializedConditionals($call[1]) as $s) {
1454-
if (!$this->get($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1462+
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) {
14551463
return;
14561464
}
14571465
}
14581466

1459-
call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions));
1467+
call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices));
14601468
}
14611469

14621470
/**
@@ -1466,14 +1474,11 @@ private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitio
14661474
* @param object $service
14671475
* @param string|null $id
14681476
*/
1469-
private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions)
1477+
private function shareService(Definition $definition, $service, $id, array &$inlineServices)
14701478
{
1471-
if (!$definition->isShared()) {
1472-
return;
1473-
}
1474-
if (null === $id) {
1475-
$inlinedDefinitions[$definition] = $service;
1476-
} else {
1479+
$inlineServices[null !== $id ? $id : spl_object_hash($definition)] = $service;
1480+
1481+
if (null !== $id && $definition->isShared()) {
14771482
$this->services[$id] = $service;
14781483
unset($this->loading[$id], $this->alreadyLoading[$id]);
14791484
}

0 commit comments

Comments
 (0)
0