Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9ad3a37

Browse files
committed
[DependencyInjection] Fix fetching lazy non-shared services multiple times
1 parent 0be2622 commit 9ad3a37

File tree

6 files changed

+239
-5
lines changed

6 files changed

+239
-5
lines changed

src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,17 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
7070

7171
if ($definition->isShared()) {
7272
$instantiation .= sprintf(' $this->%s[%s] =', $definition->isPublic() && !$definition->isPrivate() ? 'services' : 'privates', var_export($id, true));
73+
$nonSharedCode = '';
74+
} else {
75+
$nonSharedCode = sprintf(' || %s === $lazyLoad', var_export($id, true));
7376
}
7477

7578
$asGhostObject = str_contains($factoryCode, '$proxy');
7679
$proxyClass = $this->getProxyClass($definition, $asGhostObject);
7780

7881
if (!$asGhostObject) {
7982
return <<<EOF
80-
if (true === \$lazyLoad) {
83+
if (true === \$lazyLoad$nonSharedCode) {
8184
$instantiation \$this->createProxy('$proxyClass', fn () => \\$proxyClass::createLazyProxy(fn () => $factoryCode));
8285
}
8386
@@ -92,7 +95,7 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
9295
}
9396

9497
return <<<EOF
95-
if (true === \$lazyLoad) {
98+
if (true === \$lazyLoad$nonSharedCode) {
9699
$instantiation \$this->createProxy('$proxyClass', fn () => \\$proxyClass::createLazyGhost($factoryCode));
97100
}
98101

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

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,39 @@ public function testInlinedDefinitionReferencingServiceContainer()
692692
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services13.php', $dumper->dump(), '->dump() dumps inline definitions which reference service_container');
693693
}
694694

695+
public function testNonSharedLazy()
696+
{
697+
$container = new ContainerBuilder();
698+
699+
$container
700+
->register('foo', Foo::class)
701+
->setFile(realpath(self::$fixturesPath.'/includes/foo_lazy.php'))
702+
->setShared(false)
703+
->setLazy(true)
704+
->setPublic(true);
705+
706+
$container->compile();
707+
$dumper = new PhpDumper($container);
708+
$dump = $dumper->dump([
709+
'class' => 'Symfony_DI_PhpDumper_Service_Non_Shared_Lazy',
710+
'file' => __DIR__,
711+
'inline_factories_parameter' => false,
712+
'inline_class_loader_parameter' => false,
713+
]);
714+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_non_shared_lazy_public.php', $dump);
715+
eval('?>'.$dump);
716+
717+
$container = new \Symfony_DI_PhpDumper_Service_Non_Shared_Lazy();
718+
719+
$foo1 = $container->get('foo');
720+
$this->assertTrue($foo1->resetLazyObject());
721+
722+
$foo2 = $container->get('foo');
723+
$this->assertTrue($foo2->resetLazyObject());
724+
725+
$this->assertNotSame($foo1, $foo2);
726+
}
727+
695728
/**
696729
* @testWith [false]
697730
* [true]
@@ -700,7 +733,7 @@ public function testNonSharedLazyDefinitionReferences(bool $asGhostObject)
700733
{
701734
$container = new ContainerBuilder();
702735
$container->register('foo', 'stdClass')->setShared(false)->setLazy(true);
703-
$container->register('bar', 'stdClass')->addArgument(new Reference('foo', ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, false))->setPublic(true);
736+
$container->register('bar', 'stdClass')->addArgument(new Reference('foo', ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE))->setPublic(true);
704737
$container->compile();
705738

706739
$dumper = new PhpDumper($container);
@@ -1459,6 +1492,37 @@ public function testLazyWither()
14591492
$this->assertTrue($wither->resetLazyObject());
14601493
}
14611494

1495+
public function testLazyWitherNonShared()
1496+
{
1497+
$container = new ContainerBuilder();
1498+
$container->register(Foo::class);
1499+
1500+
$container
1501+
->register('wither', Wither::class)
1502+
->setShared(false)
1503+
->setLazy(true)
1504+
->setPublic(true)
1505+
->setAutowired(true);
1506+
1507+
$container->compile();
1508+
$dumper = new PhpDumper($container);
1509+
$dump = $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Service_Wither_Lazy_Non_Shared']);
1510+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_wither_lazy_non_shared.php', $dump);
1511+
eval('?>'.$dump);
1512+
1513+
$container = new \Symfony_DI_PhpDumper_Service_Wither_Lazy_Non_Shared();
1514+
1515+
$wither1 = $container->get('wither');
1516+
$this->assertInstanceOf(Foo::class, $wither1->foo);
1517+
$this->assertTrue($wither1->resetLazyObject());
1518+
1519+
$wither2 = $container->get('wither');
1520+
$this->assertInstanceOf(Foo::class, $wither2->foo);
1521+
$this->assertTrue($wither2->resetLazyObject());
1522+
1523+
$this->assertNotSame($wither1, $wither2);
1524+
}
1525+
14621526
public function testWitherWithStaticReturnType()
14631527
{
14641528
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class getNonSharedFooService extends ProjectServiceContainer
2121
{
2222
$container->factories['non_shared_foo'] ??= fn () => self::do($container);
2323

24-
if (true === $lazyLoad) {
24+
if (true === $lazyLoad || 'non_shared_foo' === $lazyLoad) {
2525
return $container->createProxy('FooLazyClassGhostF814e3a', fn () => \FooLazyClassGhostF814e3a::createLazyGhost(fn ($proxy) => self::do($container, $proxy)));
2626
}
2727

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_ghost.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ protected function getFooService($lazyLoad = true)
6767
{
6868
$this->factories['service_container']['foo'] ??= $this->getFooService(...);
6969

70-
if (true === $lazyLoad) {
70+
if (true === $lazyLoad || 'foo' === $lazyLoad) {
7171
return $this->createProxy('stdClassGhost5a8a5eb', fn () => \stdClassGhost5a8a5eb::createLazyGhost($this->getFooService(...)));
7272
}
7373

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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\LogicException;
7+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
11+
12+
/**
13+
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
14+
*/
15+
class Symfony_DI_PhpDumper_Service_Non_Shared_Lazy extends Container
16+
{
17+
protected $parameters = [];
18+
19+
public function __construct()
20+
{
21+
$this->services = $this->privates = [];
22+
$this->methodMap = [
23+
'foo' => 'getFooService',
24+
];
25+
26+
$this->aliases = [];
27+
}
28+
29+
public function compile(): void
30+
{
31+
throw new LogicException('You cannot compile a dumped container that was already compiled.');
32+
}
33+
34+
public function isCompiled(): bool
35+
{
36+
return true;
37+
}
38+
39+
protected function createProxy($class, \Closure $factory)
40+
{
41+
return $factory();
42+
}
43+
44+
/**
45+
* Gets the public 'foo' service.
46+
*
47+
* @return \Symfony\Component\DependencyInjection\Tests\Compiler\Foo
48+
*/
49+
protected function getFooService($lazyLoad = true)
50+
{
51+
$this->factories['foo'] ??= $this->getFooService(...);
52+
53+
if (true === $lazyLoad || 'foo' === $lazyLoad) {
54+
return $this->createProxy('FooGhostCf082ac', fn () => \FooGhostCf082ac::createLazyGhost($this->getFooService(...)));
55+
}
56+
57+
static $include = true;
58+
59+
if ($include) {
60+
include_once __DIR__.'/Fixtures/includes/foo_lazy.php';
61+
62+
$include = false;
63+
}
64+
65+
return $lazyLoad;
66+
}
67+
}
68+
69+
class FooGhostCf082ac extends \Symfony\Component\DependencyInjection\Tests\Compiler\Foo implements \Symfony\Component\VarExporter\LazyObjectInterface
70+
{
71+
use \Symfony\Component\VarExporter\LazyGhostTrait;
72+
73+
private const LAZY_OBJECT_PROPERTY_SCOPES = [];
74+
}
75+
76+
// Help opcache.preload discover always-needed symbols
77+
class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class);
78+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class);
79+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class);
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\LogicException;
7+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
11+
12+
/**
13+
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
14+
*/
15+
class Symfony_DI_PhpDumper_Service_Wither_Lazy_Non_Shared extends Container
16+
{
17+
protected $parameters = [];
18+
19+
public function __construct()
20+
{
21+
$this->services = $this->privates = [];
22+
$this->methodMap = [
23+
'wither' => 'getWitherService',
24+
];
25+
26+
$this->aliases = [];
27+
}
28+
29+
public function compile(): void
30+
{
31+
throw new LogicException('You cannot compile a dumped container that was already compiled.');
32+
}
33+
34+
public function isCompiled(): bool
35+
{
36+
return true;
37+
}
38+
39+
public function getRemovedIds(): array
40+
{
41+
return [
42+
'Symfony\\Component\\DependencyInjection\\Tests\\Compiler\\Foo' => true,
43+
];
44+
}
45+
46+
protected function createProxy($class, \Closure $factory)
47+
{
48+
return $factory();
49+
}
50+
51+
/**
52+
* Gets the public 'wither' autowired service.
53+
*
54+
* @return \Symfony\Component\DependencyInjection\Tests\Compiler\Wither
55+
*/
56+
protected function getWitherService($lazyLoad = true)
57+
{
58+
$this->factories['wither'] ??= $this->getWitherService(...);
59+
60+
if (true === $lazyLoad || 'wither' === $lazyLoad) {
61+
return $this->createProxy('WitherProxy8cb632f', fn () => \WitherProxy8cb632f::createLazyProxy(fn () => $this->getWitherService(false)));
62+
}
63+
64+
$instance = new \Symfony\Component\DependencyInjection\Tests\Compiler\Wither();
65+
66+
$a = ($this->privates['Symfony\\Component\\DependencyInjection\\Tests\\Compiler\\Foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo());
67+
68+
$instance = $instance->withFoo1($a);
69+
$instance = $instance->withFoo2($a);
70+
$instance->setFoo($a);
71+
72+
return $instance;
73+
}
74+
}
75+
76+
class WitherProxy8cb632f extends \Symfony\Component\DependencyInjection\Tests\Compiler\Wither implements \Symfony\Component\VarExporter\LazyObjectInterface
77+
{
78+
use \Symfony\Component\VarExporter\LazyProxyTrait;
79+
80+
private const LAZY_OBJECT_PROPERTY_SCOPES = [
81+
'foo' => [parent::class, 'foo', null],
82+
];
83+
}
84+
85+
// Help opcache.preload discover always-needed symbols
86+
class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class);
87+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class);
88+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class);

0 commit comments

Comments
 (0)