Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit9d54a4a

Browse files
[DependencyInjection] Add support for generating lazy closures
1 parent2f1ccef commit9d54a4a

File tree

7 files changed

+151
-3
lines changed

7 files changed

+151
-3
lines changed

‎src/Symfony/Component/DependencyInjection/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ CHANGELOG
1515
* Allow to trim XML service parameters value by using`trim="true"` attribute
1616
* Allow extending the`Autowire` attribute
1717
* Add`#[Exclude]` to skip autoregistering a class
18+
* Add support for generating lazy closures
1819
* Add support for autowiring services as closures using`#[AutowireCallable]` or`#[AutowireServiceClosure]`
1920

2021
6.2

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,12 +1048,35 @@ private function createService(Definition $definition, array &$inlineServices, b
10481048
}
10491049

10501050
$parameterBag =$this->getParameterBag();
1051+
$class = ($parameterBag->resolveValue($definition->getClass()) ?: (['Closure','fromCallable'] ===$definition->getFactory() ?'Closure' :null));
10511052

1052-
if (true ===$tryProxy &&$definition->isLazy() && !$tryProxy = !($proxy =$this->proxyInstantiator ??=newLazyServiceInstantiator()) ||$proxyinstanceof RealServiceInstantiator) {
1053+
if ('Closure' ===$class &&$definition->isLazy() && ['Closure','fromCallable'] ===$definition->getFactory()) {
1054+
$callable =$parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArgument(0)));
1055+
1056+
if ($callableinstanceof Reference ||$callableinstanceof Definition) {
1057+
$callable = [$callable,'__invoke'];
1058+
}
1059+
1060+
if (\is_array($callable) && (
1061+
$callable[0]instanceof Reference
1062+
||$callable[0]instanceof Definition && !isset($inlineServices[spl_object_hash($callable[0])])
1063+
)) {
1064+
$proxy =function (...$arguments)use ($callable, &$inlineServices) {
1065+
return$this->doResolveServices($callable,$inlineServices)(...$arguments);
1066+
};
1067+
$this->shareService($definition,$proxy,$id,$inlineServices);
1068+
1069+
return$proxy;
1070+
}
1071+
}
1072+
1073+
if (true ===$tryProxy &&$definition->isLazy() &&'Closure' !==$class
1074+
&& !$tryProxy = !($proxy =$this->proxyInstantiator ??=newLazyServiceInstantiator()) ||$proxyinstanceof RealServiceInstantiator
1075+
) {
10531076
$proxy =$proxy->instantiateProxy(
10541077
$this,
10551078
(clone$definition)
1056-
->setClass($parameterBag->resolveValue($definition->getClass()))
1079+
->setClass($class)
10571080
->setTags(($definition->hasTag('proxy') ? ['proxy' =>$parameterBag->resolveValue($definition->getTag('proxy'))] : []) +$definition->getTags()),
10581081
$id,function ($proxy =false)use ($definition, &$inlineServices,$id) {
10591082
return$this->createService($definition,$inlineServices,true,$id,$proxy);
@@ -1102,7 +1125,7 @@ private function createService(Definition $definition, array &$inlineServices, b
11021125
}
11031126
}
11041127
}else {
1105-
$r =new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
1128+
$r =new \ReflectionClass($class);
11061129

11071130
if (\is_object($tryProxy)) {
11081131
if ($r->getConstructor()) {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,15 @@ private function addNewInstance(Definition $definition, string $return = '', str
11791179
thrownewRuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).',$callable[1] ?:'n/a'));
11801180
}
11811181

1182+
if (['...'] ===$arguments &&$definition->isLazy() &&'Closure' === ($definition->getClass() ??'Closure') && (
1183+
$callable[0]instanceof Reference
1184+
|| ($callable[0]instanceof Definition && !$this->definitionVariables->contains($callable[0]))
1185+
)) {
1186+
$this->addContainerRef =true;
1187+
1188+
return$return.sprintf('function (...$arguments) use ($containerRef) { $container = $containerRef->get(); return (%s)->%s(...$arguments); }',$this->dumpValue($callable[0]),$callable[1]).$tail;
1189+
}
1190+
11821191
if ($callable[0]instanceof Reference
11831192
|| ($callable[0]instanceof Definition &&$this->definitionVariables->contains($callable[0]))
11841193
) {
@@ -2327,6 +2336,10 @@ private function isProxyCandidate(Definition $definition, ?bool &$asGhostObject,
23272336
{
23282337
$asGhostObject =false;
23292338

2339+
if ('Closure' === ($definition->getClass() ?: (['Closure','fromCallable'] ===$definition->getFactory() ?'Closure' :null))) {
2340+
returnnull;
2341+
}
2342+
23302343
if (!$definition->isLazy() || !$this->hasProxyDumper) {
23312344
returnnull;
23322345
}

‎src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,24 @@ public function testNamedArgumentBeforeCompile()
19611961

19621962
$this->assertSame(1,$e->first);
19631963
}
1964+
1965+
publicfunctiontestLazyClosure()
1966+
{
1967+
$container =newContainerBuilder();
1968+
$container->register('closure','Closure')
1969+
->setPublic('true')
1970+
->setFactory(['Closure','fromCallable'])
1971+
->setLazy(true)
1972+
->setArguments([[newReference('foo'),'cloneFoo']]);
1973+
$container->register('foo', Foo::class);
1974+
$container->compile();
1975+
1976+
$cloned = Foo::$cloned;
1977+
$this->assertInstanceOf(\Closure::class,$container->get('closure'));
1978+
$this->assertSame($cloned, Foo::$cloned);
1979+
$this->assertInstanceOf(Foo::class,$container->get('closure')());
1980+
$this->assertSame(1 +$cloned, Foo::$cloned);
1981+
}
19641982
}
19651983

19661984
class FooClass

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,31 @@ public function testAutowireClosure()
16861686
$this->assertInstanceOf(Foo::class,$fooClone = ($bar->buz)());
16871687
$this->assertNotSame($container->get('foo'),$fooClone);
16881688
}
1689+
1690+
publicfunctiontestLazyClosure()
1691+
{
1692+
$container =newContainerBuilder();
1693+
$container->register('closure','Closure')
1694+
->setPublic('true')
1695+
->setFactory(['Closure','fromCallable'])
1696+
->setLazy(true)
1697+
->setArguments([[newReference('foo'),'cloneFoo']]);
1698+
$container->register('foo', Foo::class);
1699+
$container->compile();
1700+
$dumper =newPhpDumper($container);
1701+
1702+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/lazy_closure.php',$dumper->dump(['class' =>'Symfony_DI_PhpDumper_Test_Lazy_Closure']));
1703+
1704+
requireself::$fixturesPath.'/php/lazy_closure.php';
1705+
1706+
$container =new \Symfony_DI_PhpDumper_Test_Lazy_Closure();
1707+
1708+
$cloned = Foo::$cloned;
1709+
$this->assertInstanceOf(\Closure::class,$container->get('closure'));
1710+
$this->assertSame($cloned, Foo::$cloned);
1711+
$this->assertInstanceOf(Foo::class,$container->get('closure')());
1712+
$this->assertSame(1 +$cloned, Foo::$cloned);
1713+
}
16891714
}
16901715

16911716
class Rot13EnvVarProcessorimplements EnvVarProcessorInterface

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313

1414
class Foo
1515
{
16+
publicstaticint$cloned =0;
17+
1618
/**
1719
* @required
1820
*/
1921
publicfunctioncloneFoo():static
2022
{
23+
++self::$cloned;
24+
2125
returnclone$this;
2226
}
2327
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
useSymfony\Component\DependencyInjection\Argument\RewindableGenerator;
4+
useSymfony\Component\DependencyInjection\ContainerInterface;
5+
useSymfony\Component\DependencyInjection\Container;
6+
useSymfony\Component\DependencyInjection\Exception\LogicException;
7+
useSymfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
8+
useSymfony\Component\DependencyInjection\Exception\RuntimeException;
9+
useSymfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
10+
useSymfony\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_Test_Lazy_Closureextends Container
16+
{
17+
protected$parameters = [];
18+
protectedreadonly\WeakReference$ref;
19+
20+
publicfunction__construct()
21+
{
22+
$this->ref = \WeakReference::create($this);
23+
$this->services =$this->privates = [];
24+
$this->methodMap = [
25+
'closure' =>'getClosureService',
26+
];
27+
28+
$this->aliases = [];
29+
}
30+
31+
publicfunctioncompile():void
32+
{
33+
thrownewLogicException('You cannot compile a dumped container that was already compiled.');
34+
}
35+
36+
publicfunctionisCompiled():bool
37+
{
38+
returntrue;
39+
}
40+
41+
publicfunctiongetRemovedIds():array
42+
{
43+
return [
44+
'foo' =>true,
45+
];
46+
}
47+
48+
protectedfunctioncreateProxy($class,\Closure$factory)
49+
{
50+
return$factory();
51+
}
52+
53+
/**
54+
* Gets the public 'closure' shared service.
55+
*
56+
* @return \Closure
57+
*/
58+
protectedstaticfunctiongetClosureService($container,$lazyLoad =true)
59+
{
60+
$containerRef =$container->ref;
61+
62+
return$container->services['closure'] =function (...$arguments)use ($containerRef) {$container =$containerRef->get();return (new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())->cloneFoo(...$arguments); };
63+
}
64+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp