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

Commit613dd45

Browse files
[DependencyInjection][ProxyManager] Use lazy-loading ghost object proxies when possible
1 parentbbf25d6 commit613dd45

File tree

13 files changed

+161
-78
lines changed

13 files changed

+161
-78
lines changed

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

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,38 @@ protected function resetService($name): void
5050
if (!$managerinstanceof LazyLoadingInterface) {
5151
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".'));
5252
}
53+
54+
$load = \Closure::bind(function ()use ($name) {
55+
if (isset($this->aliases[$name])) {
56+
$name =$this->aliases[$name];
57+
}
58+
if (isset($this->fileMap[$name])) {
59+
returnfn ($lazyLoad) =>$this->load($this->fileMap[$name],$lazyLoad);
60+
}
61+
62+
return$this->{$this->methodMap[$name]}(...);
63+
},$this->container, Container::class)();
64+
5365
if ($managerinstanceof GhostObjectInterface) {
54-
thrownew \LogicException('Resetting a lazy-ghost-object manager service is not supported.');
55-
}
56-
$manager->setProxyInitializer(\Closure::bind(
57-
function (&$wrappedInstance,LazyLoadingInterface$manager)use ($name) {
58-
if (isset($this->aliases[$name])) {
59-
$name =$this->aliases[$name];
60-
}
61-
if (isset($this->fileMap[$name])) {
62-
$wrappedInstance =$this->load($this->fileMap[$name],false);
63-
}else {
64-
$wrappedInstance =$this->{$this->methodMap[$name]}(false);
66+
$initializer =function (GhostObjectInterface$manager,string$method,array$parameters, &$initializer,array$properties)use ($load) {
67+
$instance =$load($manager);
68+
$initializer =null;
69+
70+
if ($instance !==$manager) {
71+
thrownew \LogicException(sprintf('A lazy initializer should return the ghost object proxy it was given as argument, but an instance of "%s" was returned.',get_debug_type($instance)));
6572
}
6673

74+
returntrue;
75+
};
76+
}else {
77+
$initializer =function (&$wrappedInstance,LazyLoadingInterface$manager)use ($load) {
78+
$wrappedInstance =$load(false);
6779
$manager->setProxyInitializer(null);
6880

6981
returntrue;
70-
},
71-
$this->container,
72-
Container::class
73-
));
82+
};
83+
}
84+
85+
$manager->setProxyInitializer($initializer);
7486
}
7587
}

‎src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
namespaceSymfony\Bridge\Doctrine\Tests;
1313

1414
usePHPUnit\Framework\TestCase;
15-
useProxyManager\Proxy\LazyLoadingInterface;
16-
useProxyManager\Proxy\ValueHolderInterface;
15+
useProxyManager\Proxy\GhostObjectInterface;
1716
useSymfony\Bridge\Doctrine\ManagerRegistry;
1817
useSymfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
1918
useSymfony\Bridge\ProxyManager\Tests\LazyProxy\Dumper\PhpDumperTest;
@@ -38,13 +37,16 @@ public function testResetService()
3837
$registry->setTestContainer($container);
3938

4039
$foo =$container->get('foo');
41-
$foo->bar =123;
42-
$this->assertTrue(isset($foo->bar));
4340

41+
$foo->bar =234;
42+
$this->assertSame(234,$foo->bar);
4443
$registry->resetManager();
4544

45+
self::assertFalse($foo->isProxyInitialized());
46+
$foo->initializeProxy();
47+
4648
$this->assertSame($foo,$container->get('foo'));
47-
$this->assertObjectNotHasAttribute('bar',$foo);
49+
$this->assertSame(123,$foo->bar);
4850
}
4951

5052
/**
@@ -77,8 +79,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
7779
$service =$container->get('foo');
7880

7981
self::assertInstanceOf(\stdClass::class,$service);
80-
self::assertInstanceOf(LazyLoadingInterface::class,$service);
81-
self::assertInstanceOf(ValueHolderInterface::class,$service);
82+
self::assertInstanceOf(GhostObjectInterface::class,$service);
8283
self::assertFalse($service->isProxyInitialized());
8384

8485
$service->initializeProxy();
@@ -87,12 +88,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
8788
self::assertTrue($service->isProxyInitialized());
8889

8990
$registry->resetManager();
90-
$service->initializeProxy();
91-
92-
$wrappedValue =$service->getWrappedValueHolderValue();
93-
self::assertInstanceOf(\stdClass::class,$wrappedValue);
94-
self::assertNotInstanceOf(LazyLoadingInterface::class,$wrappedValue);
95-
self::assertNotInstanceOf(ValueHolderInterface::class,$wrappedValue);
91+
self::assertFalse($service->isProxyInitialized());
9692
}
9793

9894
privatefunctiondumpLazyServiceProjectAsFilesServiceContainer()
@@ -104,6 +100,7 @@ private function dumpLazyServiceProjectAsFilesServiceContainer()
104100
$container =newContainerBuilder();
105101

106102
$container->register('foo', \stdClass::class)
103+
->setProperty('bar',123)
107104
->setPublic(true)
108105
->setLazy(true);
109106
$container->compile();

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
"symfony/stopwatch":"^5.4|^6.0",
2929
"symfony/cache":"^5.4|^6.0",
3030
"symfony/config":"^5.4|^6.0",
31-
"symfony/dependency-injection":"^5.4|^6.0",
31+
"symfony/dependency-injection":"^6.2",
3232
"symfony/form":"^5.4.9|^6.0.9",
3333
"symfony/http-kernel":"^5.4|^6.0",
3434
"symfony/messenger":"^5.4|^6.0",
3535
"symfony/doctrine-messenger":"^5.4|^6.0",
3636
"symfony/property-access":"^5.4|^6.0",
3737
"symfony/property-info":"^5.4|^6.0",
38-
"symfony/proxy-manager-bridge":"^5.4|^6.0",
38+
"symfony/proxy-manager-bridge":"^6.2",
3939
"symfony/security-core":"^6.0",
4040
"symfony/expression-language":"^5.4|^6.0",
4141
"symfony/uid":"^5.4|^6.0",
@@ -55,7 +55,7 @@
5555
"doctrine/orm":"<2.7.4",
5656
"phpunit/phpunit":"<5.4.3",
5757
"symfony/cache":"<5.4",
58-
"symfony/dependency-injection":"<5.4",
58+
"symfony/dependency-injection":"<6.2",
5959
"symfony/form":"<5.4",
6060
"symfony/http-kernel":"<5.4",
6161
"symfony/messenger":"<5.4",

‎src/Symfony/Bridge/ProxyManager/Internal/ProxyGenerator.php‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespaceSymfony\Bridge\ProxyManager\Internal;
1313

1414
useLaminas\Code\Generator\ClassGenerator;
15+
useProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
1516
useProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
1617
useProxyManager\ProxyGenerator\ProxyGeneratorInterface;
1718
useSymfony\Component\DependencyInjection\Definition;
@@ -21,12 +22,22 @@
2122
*/
2223
class ProxyGeneratorimplements ProxyGeneratorInterface
2324
{
25+
privatereadonlyProxyGeneratorInterface$generator;
26+
27+
publicfunctionasGhostObject(bool$asGhostObject):static
28+
{
29+
$clone =clone$this;
30+
$clone->generator =$asGhostObject ?newLazyLoadingGhostGenerator() :newLazyLoadingValueHolderGenerator();
31+
32+
return$clone;
33+
}
34+
2435
/**
2536
* {@inheritdoc}
2637
*/
2738
publicfunctiongenerate(\ReflectionClass$originalClass,ClassGenerator$classGenerator,array$proxyOptions = []):void
2839
{
29-
(newLazyLoadingValueHolderGenerator())->generate($originalClass,$classGenerator,$proxyOptions);
40+
$this->generator->generate($originalClass,$classGenerator,$proxyOptions);
3041

3142
foreach ($classGenerator->getMethods()as$method) {
3243
if (str_starts_with($originalClass->getFilename(),__FILE__)) {
@@ -41,18 +52,30 @@ public function generate(\ReflectionClass $originalClass, ClassGenerator $classG
4152
}
4253
}
4354

44-
publicfunctiongetProxifiedClass(Definition$definition): ?string
55+
publicfunctiongetProxifiedClass(Definition$definition,bool &$asGhostObject =null): ?string
4556
{
4657
if (!$definition->hasTag('proxy')) {
4758
if (!($class =$definition->getClass()) || !(class_exists($class) ||interface_exists($class,false))) {
4859
returnnull;
4960
}
5061

51-
return (new \ReflectionClass($class))->name;
62+
$class =new \ReflectionClass($class);
63+
$name =$class->name;
64+
65+
if ($asGhostObject = !$class->isAbstract() && !$class->isInterface() && ('stdClass' ===$class->name || !$class->isInternal())) {
66+
while ($class =$class->getParentClass()) {
67+
if (!$asGhostObject ='stdClass' ===$class->name || !$class->isInternal()) {
68+
break;
69+
}
70+
}
71+
}
72+
73+
return$name;
5274
}
5375
if (!$definition->isLazy()) {
5476
thrownew \InvalidArgumentException(sprintf('Invalid definition for service of class "%s": setting the "proxy" tag on a service requires it to be "lazy".',$definition->getClass()));
5577
}
78+
$asGhostObject =false;
5679
$tags =$definition->getTag('proxy');
5780
if (!isset($tags[0]['interface'])) {
5881
thrownew \InvalidArgumentException(sprintf('Invalid definition for service of class "%s": the "interface" attribute is missing on the "proxy" tag.',$definition->getClass()));

‎src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php‎

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespaceSymfony\Bridge\ProxyManager\LazyProxy\Instantiator;
1313

1414
useProxyManager\Configuration;
15+
useProxyManager\Factory\LazyLoadingGhostFactory;
1516
useProxyManager\Factory\LazyLoadingValueHolderFactory;
1617
useProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
18+
useProxyManager\Proxy\GhostObjectInterface;
1719
useProxyManager\Proxy\LazyLoadingInterface;
1820
useSymfony\Bridge\ProxyManager\Internal\LazyLoadingFactoryTrait;
1921
useSymfony\Bridge\ProxyManager\Internal\ProxyGenerator;
@@ -43,18 +45,36 @@ public function __construct()
4345
*/
4446
publicfunctioninstantiateProxy(ContainerInterface$container,Definition$definition,string$id,callable$realInstantiator):object
4547
{
46-
$proxifiedClass =new \ReflectionClass($this->generator->getProxifiedClass($definition));
48+
$proxifiedClass =new \ReflectionClass($this->generator->getProxifiedClass($definition,$asGhostObject));
49+
$generator =$this->generator->asGhostObject($asGhostObject);
4750

48-
$factory =newclass($this->config,$this->generator)extends LazyLoadingValueHolderFactory {
49-
use LazyLoadingFactoryTrait;
50-
};
51+
if ($asGhostObject) {
52+
$factory =newclass($this->config,$generator)extends LazyLoadingGhostFactory {
53+
use LazyLoadingFactoryTrait;
54+
};
5155

52-
$initializer =staticfunction (&$wrappedInstance,LazyLoadingInterface$proxy)use ($realInstantiator) {
53-
$wrappedInstance =$realInstantiator();
54-
$proxy->setProxyInitializer(null);
56+
$initializer =staticfunction (GhostObjectInterface$proxy,string$method,array$parameters, &$initializer,array$properties)use ($realInstantiator) {
57+
$instance =$realInstantiator($proxy);
58+
$initializer =null;
5559

56-
returntrue;
57-
};
60+
if ($instance !==$proxy) {
61+
thrownew \LogicException(sprintf('A lazy initializer should return the ghost object proxy it was given as argument, but an instance of "%s" was returned.',get_debug_type($instance)));
62+
}
63+
64+
returntrue;
65+
};
66+
}else {
67+
$factory =newclass($this->config,$generator)extends LazyLoadingValueHolderFactory {
68+
use LazyLoadingFactoryTrait;
69+
};
70+
71+
$initializer =staticfunction (&$wrappedInstance,LazyLoadingInterface$proxy)use ($realInstantiator) {
72+
$wrappedInstance =$realInstantiator();
73+
$proxy->setProxyInitializer(null);
74+
75+
returntrue;
76+
};
77+
}
5878

5979
return$factory->createProxy($proxifiedClass->name,$initializer, [
6080
'fluentSafe' =>$definition->hasTag('proxy'),

‎src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ public function __construct(string $salt = '')
4242
*/
4343
publicfunctionisProxyCandidate(Definition$definition,bool &$asGhostObject =null):bool
4444
{
45-
$asGhostObject =false;
46-
47-
return ($definition->isLazy() ||$definition->hasTag('proxy')) &&$this->proxyGenerator->getProxifiedClass($definition);
45+
return ($definition->isLazy() ||$definition->hasTag('proxy')) &&$this->proxyGenerator->getProxifiedClass($definition,$asGhostObject);
4846
}
4947

5048
/**
@@ -58,9 +56,30 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
5856
$instantiation .=sprintf(' $this->%s[%s] =',$definition->isPublic() && !$definition->isPrivate() ?'services' :'privates',var_export($id,true));
5957
}
6058

61-
$proxifiedClass =new \ReflectionClass($this->proxyGenerator->getProxifiedClass($definition));
59+
$proxifiedClass =new \ReflectionClass($this->proxyGenerator->getProxifiedClass($definition,$asGhostObject));
6260
$proxyClass =$this->getProxyClassName($proxifiedClass->name);
6361

62+
if ($asGhostObject) {
63+
return<<<EOF
64+
if (true ===\$lazyLoad) {
65+
$instantiation\$this->createProxy('$proxyClass', function () {
66+
return \\$proxyClass::staticProxyConstructor(function (\ProxyManager\Proxy\GhostObjectInterface\$proxy, string\$method, array\$parameters, &\$initializer, array\$properties) {
67+
\$instance =$factoryCode;
68+
\$initializer = null;
69+
70+
if (\$instance !==\$proxy) {
71+
throw new \LogicException(sprintf('A lazy initializer should return the ghost object proxy it was given as argument, but an instance of "%s" was returned.', get_debug_type(\$instance)));
72+
}
73+
74+
return true;
75+
});
76+
});
77+
}
78+
79+
80+
EOF;
81+
}
82+
6483
return<<<EOF
6584
if (true ===\$lazyLoad) {
6685
$instantiation\$this->createProxy('$proxyClass', function () {
@@ -96,10 +115,10 @@ private function getProxyClassName(string $class): string
96115

97116
privatefunctiongenerateProxyClass(Definition$definition):ClassGenerator
98117
{
99-
$class =$this->proxyGenerator->getProxifiedClass($definition);
118+
$class =$this->proxyGenerator->getProxifiedClass($definition,$asGhostObject);
100119
$generatedClass =newClassGenerator($this->getProxyClassName($class));
101120

102-
$this->proxyGenerator->generate(new \ReflectionClass($class),$generatedClass, [
121+
$this->proxyGenerator->asGhostObject($asGhostObject)->generate(new \ReflectionClass($class),$generatedClass, [
103122
'fluentSafe' =>$definition->hasTag('proxy'),
104123
'skipDestructor' =>true,
105124
]);

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
require_once__DIR__.'/Fixtures/includes/foo.php';
1515

1616
usePHPUnit\Framework\TestCase;
17-
useProxyManager\Proxy\LazyLoadingInterface;
17+
useProxyManager\Proxy\GhostObjectInterface;
1818
useProxyManagerBridgeFooClass;
1919
useSymfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
2020
useSymfony\Component\DependencyInjection\ContainerBuilder;
@@ -38,23 +38,21 @@ public function testCreateProxyServiceWithRuntimeInstantiator()
3838

3939
$builder->compile();
4040

41-
/* @var $foo1 \ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface */
41+
/* @var $foo1 \ProxyManager\Proxy\GhostObjectInterface */
4242
$foo1 =$builder->get('foo1');
4343

4444
$foo1->__destruct();
4545
$this->assertSame(0,$foo1::$destructorCount);
4646

4747
$this->assertSame($foo1,$builder->get('foo1'),'The same proxy is retrieved on multiple subsequent calls');
4848
$this->assertInstanceOf(ProxyManagerBridgeFooClass::class,$foo1);
49-
$this->assertInstanceOf(LazyLoadingInterface::class,$foo1);
49+
$this->assertInstanceOf(GhostObjectInterface::class,$foo1);
5050
$this->assertFalse($foo1->isProxyInitialized());
5151

5252
$foo1->initializeProxy();
5353

5454
$this->assertSame($foo1,$builder->get('foo1'),'The same proxy is retrieved after initialization');
5555
$this->assertTrue($foo1->isProxyInitialized());
56-
$this->assertInstanceOf(ProxyManagerBridgeFooClass::class,$foo1->getWrappedValueHolderValue());
57-
$this->assertNotInstanceOf(LazyLoadingInterface::class,$foo1->getWrappedValueHolderValue());
5856

5957
$foo1->__destruct();
6058
$this->assertSame(1,$foo1::$destructorCount);

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespaceSymfony\Bridge\ProxyManager\Tests\LazyProxy\Dumper;
1313

1414
usePHPUnit\Framework\TestCase;
15-
useProxyManager\Proxy\LazyLoadingInterface;
15+
useProxyManager\Proxy\GhostObjectInterface;
1616
useSymfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
1717
useSymfony\Component\DependencyInjection\ContainerBuilder;
1818
useSymfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -47,7 +47,7 @@ public function testDumpContainerWithProxyServiceWillShareProxies()
4747

4848
$proxy =$container->get('foo');
4949
$this->assertInstanceOf(\stdClass::class,$proxy);
50-
$this->assertInstanceOf(LazyLoadingInterface::class,$proxy);
50+
$this->assertInstanceOf(GhostObjectInterface::class,$proxy);
5151
$this->assertSame($proxy,$container->get('foo'));
5252

5353
$this->assertFalse($proxy->isProxyInitialized());
@@ -62,8 +62,10 @@ private function dumpLazyServiceProjectServiceContainer()
6262
{
6363
$container =newContainerBuilder();
6464

65-
$container->register('foo','stdClass')->setPublic(true);
66-
$container->getDefinition('foo')->setLazy(true);
65+
$container->register('foo','stdClass')
66+
->setPublic(true)
67+
->setLazy(true)
68+
->setProperty('bar',123);
6769
$container->compile();
6870

6971
$dumper =newPhpDumper($container);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp