Skip to content

Commit 28c3300

Browse files
[DependencyInjection][VarExporter] Fix support for lazy withers
1 parent 769b183 commit 28c3300

11 files changed

+182
-21
lines changed

ContainerBuilder.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,12 +1040,8 @@ private function createService(Definition $definition, array &$inlineServices, b
10401040
if (null !== $factory) {
10411041
$service = $factory(...$arguments);
10421042

1043-
if (\is_object($tryProxy)) {
1044-
if (\get_class($service) !== $parameterBag->resolveValue($definition->getClass())) {
1045-
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', $definition->getClass(), get_debug_type($service)));
1046-
}
1047-
1048-
$tryProxy = Hydrator::hydrate($tryProxy, (array) $service);
1043+
if (\is_object($tryProxy) && \get_class($service) !== $parameterBag->resolveValue($definition->getClass())) {
1044+
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', $definition->getClass(), get_debug_type($service)));
10491045
}
10501046

10511047
if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
@@ -1117,6 +1113,10 @@ private function createService(Definition $definition, array &$inlineServices, b
11171113
$callable($service);
11181114
}
11191115

1116+
if (\is_object($tryProxy) && $tryProxy !== $service) {
1117+
return Hydrator::hydrate($tryProxy, (array) $service);
1118+
}
1119+
11201120
return $service;
11211121
}
11221122

Dumper/PhpDumper.php

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@ private function addServiceInstance(string $id, Definition $definition, bool $is
676676

677677
$return = '';
678678
if ($isSimpleInstance) {
679+
if ($asGhostObject && null !== $definition->getFactory()) {
680+
$instantiation .= '$this->hydrateProxy($lazyLoad, ';
681+
}
679682
$return = 'return ';
680683
} else {
681684
$instantiation .= ' = ';
@@ -1058,7 +1061,7 @@ private function addInlineService(string $id, Definition $definition, Definition
10581061
if ('instance' === $name) {
10591062
$code .= $this->addServiceInstance($id, $definition, $isSimpleInstance);
10601063
} else {
1061-
$code .= $this->addNewInstance($inlineDef, ' $'.$name.' = ', $id, $asGhostObject);
1064+
$code .= $this->addNewInstance($inlineDef, ' $'.$name.' = ', $id);
10621065
}
10631066

10641067
if ('' !== $inline = $this->addInlineVariables($id, $definition, $arguments, false)) {
@@ -1072,11 +1075,15 @@ private function addInlineService(string $id, Definition $definition, Definition
10721075
$code .= $this->addServiceConfigurator($inlineDef, $name);
10731076
}
10741077

1075-
if ($isRootInstance && !$isSimpleInstance) {
1076-
$code .= "\n return \$instance;\n";
1078+
if (!$isRootInstance || $isSimpleInstance) {
1079+
return $code;
10771080
}
10781081

1079-
return $code;
1082+
if (!$asGhostObject) {
1083+
return $code."\n return \$instance;\n";
1084+
}
1085+
1086+
return $code."\n return \$this->hydrateProxy(\$lazyLoad, \$instance);\n";
10801087
}
10811088

10821089
private function addServices(array &$services = null): string
@@ -1123,7 +1130,7 @@ private function generateServiceFiles(array $services): iterable
11231130

11241131
private function addNewInstance(Definition $definition, string $return = '', string $id = null, bool $asGhostObject = false): string
11251132
{
1126-
$tail = $return ? ";\n" : '';
1133+
$tail = $return ? str_repeat(')', substr_count($return, '(') - substr_count($return, ')')).";\n" : '';
11271134

11281135
if (BaseServiceLocator::class === $definition->getClass() && $definition->hasTag($this->serviceLocatorTag)) {
11291136
$arguments = [];
@@ -1142,11 +1149,6 @@ private function addNewInstance(Definition $definition, string $return = '', str
11421149
if (null !== $definition->getFactory()) {
11431150
$callable = $definition->getFactory();
11441151

1145-
if ($asGhostObject) {
1146-
$return .= '$this->hydrateProxy($lazyLoad, ';
1147-
$tail = ')'.$tail;
1148-
}
1149-
11501152
if (['Closure', 'fromCallable'] === $callable && [0] === array_keys($definition->getArguments())) {
11511153
$callable = $definition->getArgument(0);
11521154
$arguments = ['...'];
@@ -1202,7 +1204,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
12021204
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
12031205
}
12041206

1205-
if (!method_exists($class, '__construct')) {
1207+
if (!method_exists($this->container->getParameterBag()->resolveValue($class), '__construct')) {
12061208
return $return.'$lazyLoad'.$tail;
12071209
}
12081210

@@ -1329,6 +1331,10 @@ protected function createProxy(\$class, \Closure \$factory)
13291331
13301332
protected function hydrateProxy(\$proxy, \$instance)
13311333
{
1334+
if (\$proxy === \$instance) {
1335+
return \$proxy;
1336+
}
1337+
13321338
if (!\in_array(\get_class(\$instance), [\get_class(\$proxy), get_parent_class(\$proxy)], true)) {
13331339
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1\$s".', get_parent_class(\$proxy), get_debug_type(\$instance)));
13341340
}
@@ -1880,10 +1886,7 @@ private function dumpValue(mixed $value, bool $interpolate = true): string
18801886
throw new RuntimeException('Cannot dump definitions which have a configurator.');
18811887
}
18821888

1883-
$asGhostObject = false;
1884-
$this->isProxyCandidate($value, $asGhostObject);
1885-
1886-
return $this->addNewInstance($value, '', null, $asGhostObject);
1889+
return $this->addNewInstance($value);
18871890
} elseif ($value instanceof Variable) {
18881891
return '$'.$value;
18891892
} elseif ($value instanceof Reference) {

Tests/ContainerBuilderTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,24 @@ public function testWither()
16811681
$this->assertInstanceOf(Foo::class, $wither->foo);
16821682
}
16831683

1684+
public function testLazyWither()
1685+
{
1686+
$container = new ContainerBuilder();
1687+
$container->register(Foo::class);
1688+
1689+
$container
1690+
->register('wither', Wither::class)
1691+
->setLazy(true)
1692+
->setPublic(true)
1693+
->setAutowired(true);
1694+
1695+
$container->compile();
1696+
1697+
$wither = $container->get('wither');
1698+
$this->assertInstanceOf(Foo::class, $wither->foo);
1699+
$this->assertTrue($wither->resetLazyGhostObject());
1700+
}
1701+
16841702
public function testWitherWithStaticReturnType()
16851703
{
16861704
$container = new ContainerBuilder();

Tests/Dumper/PhpDumperTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,30 @@ public function testWither()
14341434
$this->assertInstanceOf(Foo::class, $wither->foo);
14351435
}
14361436

1437+
public function testLazyWither()
1438+
{
1439+
$container = new ContainerBuilder();
1440+
$container->register(Foo::class);
1441+
1442+
$container
1443+
->register('wither', Wither::class)
1444+
->setLazy(true)
1445+
->setPublic(true)
1446+
->setAutowired(true);
1447+
1448+
$container->compile();
1449+
$dumper = new PhpDumper($container);
1450+
$dump = $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Service_Wither_Lazy']);
1451+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_wither_lazy.php', $dump);
1452+
eval('?>'.$dump);
1453+
1454+
$container = new \Symfony_DI_PhpDumper_Service_Wither_Lazy();
1455+
1456+
$wither = $container->get('wither');
1457+
$this->assertInstanceOf(Foo::class, $wither->foo);
1458+
$this->assertTrue($wither->resetLazyGhostObject());
1459+
}
1460+
14371461
public function testWitherWithStaticReturnType()
14381462
{
14391463
$container = new ContainerBuilder();

Tests/Fixtures/php/services9_lazy_inlined_factories.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ class ProjectServiceContainer extends Container
7272

7373
protected function hydrateProxy($proxy, $instance)
7474
{
75+
if ($proxy === $instance) {
76+
return $proxy;
77+
}
78+
7579
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
7680
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
7781
}

Tests/Fixtures/php/services_dedup_lazy_ghost.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ protected function createProxy($class, \Closure $factory)
4444

4545
protected function hydrateProxy($proxy, $instance)
4646
{
47+
if ($proxy === $instance) {
48+
return $proxy;
49+
}
50+
4751
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
4852
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
4953
}

Tests/Fixtures/php/services_dedup_lazy_proxy.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ protected function createProxy($class, \Closure $factory)
4444

4545
protected function hydrateProxy($proxy, $instance)
4646
{
47+
if ($proxy === $instance) {
48+
return $proxy;
49+
}
50+
4751
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
4852
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
4953
}

Tests/Fixtures/php/services_non_shared_lazy.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ protected function createProxy($class, \Closure $factory)
5050

5151
protected function hydrateProxy($proxy, $instance)
5252
{
53+
if ($proxy === $instance) {
54+
return $proxy;
55+
}
56+
5357
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
5458
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
5559
}

Tests/Fixtures/php/services_non_shared_lazy_as_files.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ class ProjectServiceContainer extends Container
126126

127127
protected function hydrateProxy($proxy, $instance)
128128
{
129+
if ($proxy === $instance) {
130+
return $proxy;
131+
}
132+
129133
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
130134
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
131135
}

Tests/Fixtures/php/services_non_shared_lazy_ghost.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ protected function createProxy($class, \Closure $factory)
5050

5151
protected function hydrateProxy($proxy, $instance)
5252
{
53+
if ($proxy === $instance) {
54+
return $proxy;
55+
}
56+
5357
if (!\in_array(\get_class($instance), [\get_class($proxy), get_parent_class($proxy)], true)) {
5458
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', get_parent_class($proxy), get_debug_type($instance)));
5559
}

0 commit comments

Comments
 (0)