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

Commitdf1a745

Browse files
[DependencyInjection] Use lazy-loading ghost object proxies out of the box
1 parent647033d commitdf1a745

File tree

19 files changed

+279
-49
lines changed

19 files changed

+279
-49
lines changed

‎src/Symfony/Bridge/Doctrine/ManagerRegistry.php‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
useProxyManager\Proxy\LazyLoadingInterface;
1717
useSymfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
1818
useSymfony\Component\DependencyInjection\Container;
19+
useSymfony\Component\VarExporter\LazyGhostObjectInterface;
1920

2021
/**
2122
* References Doctrine connections and entity/document managers.
@@ -47,6 +48,11 @@ protected function resetService($name): void
4748
}
4849
$manager =$this->container->get($name);
4950

51+
if ($managerinstanceof LazyGhostObjectInterface) {
52+
$manager->resetLazyGhostObject();
53+
54+
return;
55+
}
5056
if (!$managerinstanceof LazyLoadingInterface) {
5157
thrownew \LogicException('Resetting a non-lazy manager service is not supported.'.(interface_exists(LazyLoadingInterface::class) &&class_exists(RuntimeInstantiator::class) ?sprintf('Declare the "%s" service as lazy.',$name) :'Try running "composer require symfony/proxy-manager-bridge".'));
5258
}

‎src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
usePHPUnit\Framework\TestCase;
1717
useProxyManager\Proxy\LazyLoadingInterface;
1818
useProxyManagerBridgeFooClass;
19-
useSymfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
2019
useSymfony\Component\DependencyInjection\ContainerBuilder;
2120

2221
/**
@@ -31,10 +30,8 @@ public function testCreateProxyServiceWithRuntimeInstantiator()
3130
{
3231
$builder =newContainerBuilder();
3332

34-
$builder->setProxyInstantiator(newRuntimeInstantiator());
35-
3633
$builder->register('foo1', ProxyManagerBridgeFooClass::class)->setFile(__DIR__.'/Fixtures/includes/foo.php')->setPublic(true);
37-
$builder->getDefinition('foo1')->setLazy(true);
34+
$builder->getDefinition('foo1')->setLazy(true)->addTag('proxy', ['interface' => ProxyManagerBridgeFooClass::class]);
3835

3936
$builder->compile();
4037

‎src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Dumper/PhpDumperTest.php‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
usePHPUnit\Framework\TestCase;
1515
useProxyManager\Proxy\LazyLoadingInterface;
16-
useSymfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
1716
useSymfony\Component\DependencyInjection\ContainerBuilder;
1817
useSymfony\Component\DependencyInjection\Dumper\PhpDumper;
1918

@@ -62,14 +61,12 @@ private function dumpLazyServiceProjectServiceContainer()
6261
{
6362
$container =newContainerBuilder();
6463

65-
$container->register('foo','stdClass')->setPublic(true);
66-
$container->getDefinition('foo')->setLazy(true);
64+
$container->register('foo',\stdClass::class)->setPublic(true);
65+
$container->getDefinition('foo')->setLazy(true)->addTag('proxy', ['interface' => \stdClass::class]);
6766
$container->compile();
6867

6968
$dumper =newPhpDumper($container);
7069

71-
$dumper->setProxyDumper(newProxyDumper());
72-
7370
return$dumper->dump(['class' =>'LazyServiceProjectServiceContainer']);
7471
}
7572
}

‎src/Symfony/Bridge/ProxyManager/composer.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
"require": {
1919
"php":">=8.1",
2020
"friendsofphp/proxy-manager-lts":"^1.0.2",
21-
"symfony/dependency-injection":"^5.4|^6.0"
21+
"symfony/dependency-injection":"^6.2"
2222
},
2323
"require-dev": {
24-
"symfony/config":"^5.4|^6.0"
24+
"symfony/config":"^6.1"
2525
},
2626
"autoload": {
2727
"psr-4": {"Symfony\\Bridge\\ProxyManager\\":"" },

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ CHANGELOG
44
6.2
55
---
66

7+
* Use lazy-loading ghost object proxies out of the box
78
* Add argument`&$asGhostObject` to LazyProxy's`DumperInterface` to allow using ghost objects for lazy loading services
89
* Add`enum` env var processor
10+
* Deprecate`RealServiceInstantiator`
911

1012
6.1
1113
---

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
useSymfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
4040
useSymfony\Component\DependencyInjection\Extension\ExtensionInterface;
4141
useSymfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
42+
useSymfony\Component\DependencyInjection\LazyProxy\Instantiator\LazyServiceInstantiator;
4243
useSymfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
4344
useSymfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
4445
useSymfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -86,7 +87,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
8687

8788
privateCompiler$compiler;
8889
privatebool$trackResources;
89-
private?InstantiatorInterface$proxyInstantiator =null;
90+
privateInstantiatorInterface$proxyInstantiator;
9091
privateExpressionLanguage$expressionLanguage;
9192

9293
/**
@@ -994,7 +995,7 @@ private function createService(Definition $definition, array &$inlineServices, b
994995
trigger_deprecation($deprecation['package'],$deprecation['version'],$deprecation['message']);
995996
}
996997

997-
if (true ===$tryProxy &&$definition->isLazy() && !$tryProxy = !($proxy =$this->proxyInstantiator) ||$proxyinstanceof RealServiceInstantiator) {
998+
if (true ===$tryProxy &&$definition->isLazy() && !$tryProxy = !($proxy =$this->proxyInstantiator ??=newLazyServiceInstantiator()) ||$proxyinstanceof RealServiceInstantiator) {
998999
$proxy =$proxy->instantiateProxy(
9991000
$this,
10001001
$definition,

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
useSymfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
3333
useSymfony\Component\DependencyInjection\ExpressionLanguage;
3434
useSymfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterfaceasProxyDumper;
35+
useSymfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper;
3536
useSymfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
3637
useSymfony\Component\DependencyInjection\Loader\FileLoader;
3738
useSymfony\Component\DependencyInjection\Parameter;
@@ -89,6 +90,7 @@ class PhpDumper extends Dumper
8990
privatestring$serviceLocatorTag;
9091
privatearray$exportedVariables = [];
9192
privatestring$baseClass;
93+
privatestring$class;
9294
privateProxyDumper$proxyDumper;
9395

9496
/**
@@ -154,6 +156,7 @@ public function dump(array $options = []): string|array
154156
$this->inlineFactories =$this->asFiles &&$options['inline_factories_parameter'] &&$this->container->hasParameter($options['inline_factories_parameter']) &&$this->container->getParameter($options['inline_factories_parameter']);
155157
$this->inlineRequires =$options['inline_class_loader_parameter'] && ($this->container->hasParameter($options['inline_class_loader_parameter']) ?$this->container->getParameter($options['inline_class_loader_parameter']) :$options['debug']);
156158
$this->serviceLocatorTag =$options['service_locator_tag'];
159+
$this->class =$options['class'];
157160

158161
if (!str_starts_with($baseClass =$options['base_class'],'\\') &&'Container' !==$baseClass) {
159162
$baseClass =sprintf('%s\%s',$options['namespace'] ?'\\'.$options['namespace'] :'',$baseClass);
@@ -401,7 +404,7 @@ class %s extends {$options['class']}
401404
*/
402405
privatefunctiongetProxyDumper():ProxyDumper
403406
{
404-
return$this->proxyDumper ??=newNullDumper();
407+
return$this->proxyDumper ??=newLazyServiceDumper($this->class);
405408
}
406409

407410
privatefunctionanalyzeReferences()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\DependencyInjection\LazyProxy\Instantiator;
13+
14+
useSymfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
15+
useSymfony\Component\DependencyInjection\ContainerInterface;
16+
useSymfony\Component\DependencyInjection\Definition;
17+
useSymfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper;
18+
useSymfony\Component\VarExporter\LazyGhostObjectInterface;
19+
useSymfony\Component\VarExporter\LazyGhostObjectTrait;
20+
21+
/**
22+
* @author Nicolas Grekas <p@tchwork.com>
23+
*/
24+
finalclass LazyServiceInstantiatorimplements InstantiatorInterface
25+
{
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
publicfunctioninstantiateProxy(ContainerInterface$container,Definition$definition,string$id,callable$realInstantiator):object
30+
{
31+
$dumper =newLazyServiceDumper();
32+
33+
if ($dumper->useProxyManager($definition)) {
34+
return (newRuntimeInstantiator())->instantiateProxy($container,$definition,$id,$realInstantiator);
35+
}
36+
37+
if (!class_exists($proxyClass =$dumper->getProxyClass($definition),false)) {
38+
eval(sprintf('class %s extends %s implements %s { use %s; }',$proxyClass,$definition->getClass(), LazyGhostObjectInterface::class, LazyGhostObjectTrait::class));
39+
}
40+
41+
return$proxyClass::createLazyGhostObject($realInstantiator);
42+
}
43+
}

‎src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
useSymfony\Component\DependencyInjection\ContainerInterface;
1515
useSymfony\Component\DependencyInjection\Definition;
1616

17+
trigger_deprecation('symfony/dependency-injection','6.2','The "%s" class is deprecated, use "%s" instead.', RealServiceInstantiator::class, LazyServiceInstantiator::class);
18+
1719
/**
1820
* {@inheritdoc}
1921
*
2022
* Noop proxy instantiator - produces the real service instead of a proxy instance.
2123
*
2224
* @author Marco Pivetta <ocramius@gmail.com>
25+
*
26+
* @deprecated since Symfony 6.2, use LazyServiceInstantiator instead.
2327
*/
2428
class RealServiceInstantiatorimplements InstantiatorInterface
2529
{
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\DependencyInjection\LazyProxy\PhpDumper;
13+
14+
useSymfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
15+
useSymfony\Component\DependencyInjection\Definition;
16+
useSymfony\Component\DependencyInjection\Exception\InvalidArgumentException;
17+
useSymfony\Component\DependencyInjection\Exception\LogicException;
18+
useSymfony\Component\VarExporter\LazyGhostObjectInterface;
19+
useSymfony\Component\VarExporter\LazyGhostObjectTrait;
20+
21+
/**
22+
* @author Nicolas Grekas <p@tchwork.com>
23+
*/
24+
finalclass LazyServiceDumperimplements DumperInterface
25+
{
26+
publicfunction__construct(
27+
privatestring$salt ='',
28+
) {
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
publicfunctionisProxyCandidate(Definition$definition,bool &$asGhostObject =null):bool
35+
{
36+
$asGhostObject =false;
37+
38+
if ($definition->hasTag('proxy')) {
39+
if (!$definition->isLazy()) {
40+
thrownewInvalidArgumentException(sprintf('Invalid definition for service of class "%s": setting the "proxy" tag on a service requires it to be "lazy".',$definition->getClass()));
41+
}
42+
43+
returntrue;
44+
}
45+
46+
if (!$definition->isLazy()) {
47+
returnfalse;
48+
}
49+
50+
if (!($class =$definition->getClass()) || !(class_exists($class) ||interface_exists($class,false))) {
51+
returnfalse;
52+
}
53+
54+
$class =new \ReflectionClass($class);
55+
56+
if ($class->isFinal()) {
57+
thrownewInvalidArgumentException(sprintf('Cannot make service of class "%s" lazy because the class is final.',$definition->getClass()));
58+
}
59+
60+
if ($asGhostObject = !$class->isAbstract() && !$class->isInterface() && (\stdClass::class ===$class->name || !$class->isInternal())) {
61+
while ($class =$class->getParentClass()) {
62+
if (!$asGhostObject = \stdClass::class ===$class->name || !$class->isInternal()) {
63+
break;
64+
}
65+
}
66+
}
67+
68+
returntrue;
69+
}
70+
71+
/**
72+
* {@inheritdoc}
73+
*/
74+
publicfunctiongetProxyFactoryCode(Definition$definition,string$id,string$factoryCode):string
75+
{
76+
if ($dumper =$this->useProxyManager($definition)) {
77+
return$dumper->getProxyFactoryCode($definition,$id,$factoryCode);
78+
}
79+
80+
$instantiation ='return';
81+
82+
if ($definition->isShared()) {
83+
$instantiation .=sprintf(' $this->%s[%s] =',$definition->isPublic() && !$definition->isPrivate() ?'services' :'privates',var_export($id,true));
84+
}
85+
86+
$proxyClass =$this->getProxyClass($definition);
87+
88+
if (preg_match('/^\$this->\w++\(\$proxy\)$/',$factoryCode)) {
89+
$factoryCode =substr_replace($factoryCode,'(...)', -8);
90+
}else {
91+
$factoryCode =sprintf('function ($proxy) { return %s; }',$factoryCode);
92+
}
93+
94+
return<<<EOF
95+
if (true ===\$lazyLoad) {
96+
$instantiation\$this->createProxy('$proxyClass', function () {
97+
return \\$proxyClass::createLazyGhostObject($factoryCode);
98+
});
99+
}
100+
101+
102+
EOF;
103+
}
104+
105+
/**
106+
* {@inheritdoc}
107+
*/
108+
publicfunctiongetProxyCode(Definition$definition):string
109+
{
110+
if ($dumper =$this->useProxyManager($definition)) {
111+
return$dumper->getProxyCode($definition);
112+
}
113+
114+
$proxyClass =$this->getProxyClass($definition);
115+
116+
returnsprintf(<<<EOF
117+
class %s extends \%s implements \%s
118+
{
119+
use \%s;
120+
}
121+
122+
EOF,
123+
$proxyClass,
124+
$definition->getClass(),
125+
LazyGhostObjectInterface::class,
126+
LazyGhostObjectTrait::class
127+
);
128+
}
129+
130+
publicfunctiongetProxyClass(Definition$definition):string
131+
{
132+
$class = (new \ReflectionClass($definition->getClass()))->name;
133+
134+
returnpreg_replace('/^.*\\\\/','',$class).'_'.substr(hash('sha256',$this->salt.'+'.$class), -7);
135+
}
136+
137+
publicfunctionuseProxyManager(Definition$definition): ?ProxyDumper
138+
{
139+
if (!$this->isProxyCandidate($definition,$asGhostObject)) {
140+
thrownewInvalidArgumentException(sprintf('Cannot instantiate lazy proxy for service of class "%s".',$definition->getClass()));
141+
}
142+
143+
if ($asGhostObject) {
144+
returnnull;
145+
}
146+
147+
if (!class_exists(ProxyDumper::class)) {
148+
thrownewLogicException('You cannot use virtual proxies for lazy services as the ProxyManager bridge is not installed. Try running "composer require symfony/proxy-manager-bridge".');
149+
}
150+
151+
returnnewProxyDumper($this->salt);
152+
}
153+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp