Skip to content

Navigation Menu

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

Appearance settings

Commit 4bcf132

Browse filesBrowse files
feature #59890 [VarExporter] Leverage native lazy objects (nicolas-grekas)
This PR was merged into the 7.3 branch. Discussion ---------- [VarExporter] Leverage native lazy objects | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT Let's leverage native lazy objects. Instead of keeping/updating LazyGhostTrait and LazyProxyTrait, I'm deprecating them in favor of using native lazy proxies directly. There is one use case that is not covered by native lazy objects: lazy decorators - aka lazy proxies built against an interface or an internal class. For this use case, we keep `ProxyHelper::generateLazyProxy()`. Commits ------- a00855a [VarExporter] Leverage native lazy objects
2 parents 146c128 + a00855a commit 4bcf132
Copy full SHA for 4bcf132

33 files changed

+981
-226
lines changed

‎UPGRADE-7.3.md

Copy file name to clipboardExpand all lines: UPGRADE-7.3.md
+7
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,10 @@ VarDumper
201201

202202
* Deprecate `ResourceCaster::castCurl()`, `ResourceCaster::castGd()` and `ResourceCaster::castOpensslX509()`
203203
* Mark all casters as `@internal`
204+
205+
VarExporter
206+
-----------
207+
208+
* Deprecate using `ProxyHelper::generateLazyProxy()` when native lazy proxies can be used - the method should be used to generate abstraction-based lazy decorators only
209+
* Deprecate `LazyGhostTrait` and `LazyProxyTrait`, use native lazy objects instead
210+
* Deprecate `ProxyHelper::generateLazyGhost()`, use native lazy objects instead

‎src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php
+6
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public function testRefreshInvalidUser()
136136
$provider->refreshUser($user2);
137137
}
138138

139+
/**
140+
* @group legacy
141+
*/
139142
public function testSupportProxy()
140143
{
141144
$em = DoctrineTestHelper::createTestEntityManager();
@@ -202,6 +205,9 @@ public function testPasswordUpgrades()
202205
$provider->upgradePassword($user, 'foobar');
203206
}
204207

208+
/**
209+
* @group legacy
210+
*/
205211
public function testRefreshedUserProxyIsLoaded()
206212
{
207213
$em = DoctrineTestHelper::createTestEntityManager();

‎src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
+3
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ public static function provideUniquenessConstraints(): iterable
223223
yield 'Named arguments' => [new UniqueEntity(message: 'myMessage', fields: ['name'], em: 'foo')];
224224
}
225225

226+
/**
227+
* @group legacy
228+
*/
226229
public function testValidateEntityWithPrivatePropertyAndProxyObject()
227230
{
228231
$entity = new SingleIntIdWithPrivateNameEntity(1, 'Foo');

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php
+17-7
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,28 @@ public function getProxyClass(Definition $definition, bool $asGhostObject, ?\Ref
187187
$class = 'object' !== $definition->getClass() ? $definition->getClass() : 'stdClass';
188188
$class = new \ReflectionClass($class);
189189

190-
if (\PHP_VERSION_ID >= 80400) {
191-
if ($asGhostObject) {
192-
return $class->name;
193-
}
190+
if (\PHP_VERSION_ID < 80400) {
191+
return preg_replace('/^.*\\\\/', '', $definition->getClass())
192+
.($asGhostObject ? 'Ghost' : 'Proxy')
193+
.ucfirst(substr(hash('xxh128', $this->salt.'+'.$class->name.'+'.serialize($definition->getTag('proxy'))), -7));
194+
}
195+
196+
if ($asGhostObject) {
197+
return $class->name;
198+
}
199+
200+
if (!$definition->hasTag('proxy') && !$class->isInterface()) {
201+
$parent = $class;
202+
do {
203+
$extendsInternalClass = $parent->isInternal();
204+
} while (!$extendsInternalClass && $parent = $parent->getParentClass());
194205

195-
if (!$definition->hasTag('proxy') && !$class->isInterface()) {
206+
if (!$extendsInternalClass) {
196207
return $class->name;
197208
}
198209
}
199210

200-
return preg_replace('/^.*\\\\/', '', $definition->getClass())
201-
.($asGhostObject ? 'Ghost' : 'Proxy')
211+
return preg_replace('/^.*\\\\/', '', $definition->getClass()).'Proxy'
202212
.ucfirst(substr(hash('xxh128', $this->salt.'+'.$class->name.'+'.serialize($definition->getTag('proxy'))), -7));
203213
}
204214
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+5-1
Original file line numberDiff line numberDiff line change
@@ -2036,7 +2036,11 @@ public function testLazyAutowireAttributeWithIntersection()
20362036

20372037
$dumper = new PhpDumper($container);
20382038

2039-
$this->assertStringEqualsFile(self::$fixturesPath.'/php/lazy_autowire_attribute_with_intersection.php', $dumper->dump());
2039+
if (\PHP_VERSION_ID >= 80400) {
2040+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/lazy_autowire_attribute_with_intersection.php', $dumper->dump());
2041+
} else {
2042+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/legacy_lazy_autowire_attribute_with_intersection.php', $dumper->dump());
2043+
}
20402044
}
20412045

20422046
public function testCallableAdapterConsumer()

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_autowire_attribute_with_intersection.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_autowire_attribute_with_intersection.php
+2-7
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,16 @@ protected static function get_Lazy_Foo_QFdMZVKService($container, $lazyLoad = tr
7474

7575
class objectProxy1fd6daa implements \Symfony\Component\DependencyInjection\Tests\Compiler\AInterface, \Symfony\Component\DependencyInjection\Tests\Compiler\IInterface, \Symfony\Component\VarExporter\LazyObjectInterface
7676
{
77-
use \Symfony\Component\VarExporter\LazyProxyTrait;
77+
use \Symfony\Component\VarExporter\Internal\LazyDecoratorTrait;
7878

7979
private const LAZY_OBJECT_PROPERTY_SCOPES = [];
8080

8181
public function initializeLazyObject(): \Symfony\Component\DependencyInjection\Tests\Compiler\AInterface&\Symfony\Component\DependencyInjection\Tests\Compiler\IInterface
8282
{
83-
if ($state = $this->lazyObjectState ?? null) {
84-
return $state->realInstance ??= ($state->initializer)();
85-
}
86-
87-
return $this;
83+
return $this->lazyObjectState->realInstance;
8884
}
8985
}
9086

9187
// Help opcache.preload discover always-needed symbols
9288
class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class);
9389
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class);
94-
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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 ProjectServiceContainer 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' shared autowired service.
46+
*
47+
* @return \Symfony\Component\DependencyInjection\Tests\Compiler\AAndIInterfaceConsumer
48+
*/
49+
protected static function getFooService($container)
50+
{
51+
$a = ($container->privates['.lazy.foo.qFdMZVK'] ?? self::get_Lazy_Foo_QFdMZVKService($container));
52+
53+
if (isset($container->services['foo'])) {
54+
return $container->services['foo'];
55+
}
56+
57+
return $container->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Compiler\AAndIInterfaceConsumer($a);
58+
}
59+
60+
/**
61+
* Gets the private '.lazy.foo.qFdMZVK' shared service.
62+
*
63+
* @return \object
64+
*/
65+
protected static function get_Lazy_Foo_QFdMZVKService($container, $lazyLoad = true)
66+
{
67+
if (true === $lazyLoad) {
68+
return $container->privates['.lazy.foo.qFdMZVK'] = $container->createProxy('objectProxy1fd6daa', static fn () => \objectProxy1fd6daa::createLazyProxy(static fn () => self::get_Lazy_Foo_QFdMZVKService($container, false)));
69+
}
70+
71+
return ($container->services['foo'] ?? self::getFooService($container));
72+
}
73+
}
74+
75+
class objectProxy1fd6daa implements \Symfony\Component\DependencyInjection\Tests\Compiler\AInterface, \Symfony\Component\DependencyInjection\Tests\Compiler\IInterface, \Symfony\Component\VarExporter\LazyObjectInterface
76+
{
77+
use \Symfony\Component\VarExporter\LazyProxyTrait;
78+
79+
private const LAZY_OBJECT_PROPERTY_SCOPES = [];
80+
81+
public function initializeLazyObject(): \Symfony\Component\DependencyInjection\Tests\Compiler\AInterface&\Symfony\Component\DependencyInjection\Tests\Compiler\IInterface
82+
{
83+
if ($state = $this->lazyObjectState ?? null) {
84+
return $state->realInstance ??= ($state->initializer)();
85+
}
86+
87+
return $this;
88+
}
89+
}
90+
91+
// Help opcache.preload discover always-needed symbols
92+
class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class);
93+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class);
94+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class);

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_dedup_lazy.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_dedup_lazy.php
+13-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected static function getBarService($container, $lazyLoad = true)
6666
protected static function getBazService($container, $lazyLoad = true)
6767
{
6868
if (true === $lazyLoad) {
69-
return $container->services['baz'] = new \ReflectionClass('stdClass')->newLazyProxy(static fn () => self::getBazService($container, false));
69+
return $container->services['baz'] = $container->createProxy('stdClassProxyAa01f12', static fn () => \stdClassProxyAa01f12::createLazyProxy(static fn () => self::getBazService($container, false)));
7070
}
7171

7272
return \foo_bar();
@@ -80,7 +80,7 @@ protected static function getBazService($container, $lazyLoad = true)
8080
protected static function getBuzService($container, $lazyLoad = true)
8181
{
8282
if (true === $lazyLoad) {
83-
return $container->services['buz'] = new \ReflectionClass('stdClass')->newLazyProxy(static fn () => self::getBuzService($container, false));
83+
return $container->services['buz'] = $container->createProxy('stdClassProxyAa01f12', static fn () => \stdClassProxyAa01f12::createLazyProxy(static fn () => self::getBuzService($container, false)));
8484
}
8585

8686
return \foo_bar();
@@ -100,3 +100,14 @@ protected static function getFooService($container, $lazyLoad = true)
100100
return $lazyLoad;
101101
}
102102
}
103+
104+
class stdClassProxyAa01f12 extends \stdClass implements \Symfony\Component\VarExporter\LazyObjectInterface
105+
{
106+
use \Symfony\Component\VarExporter\Internal\LazyDecoratorTrait;
107+
108+
private const LAZY_OBJECT_PROPERTY_SCOPES = [];
109+
}
110+
111+
// Help opcache.preload discover always-needed symbols
112+
class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class);
113+
class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class);

‎src/Symfony/Component/HttpKernel/Tests/Fixtures/LazyResettableService.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Tests/Fixtures/LazyResettableService.php
+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
1313

14-
class LazyResettableService
14+
class LazyResettableService extends \stdClass
1515
{
1616
public static $counter = 0;
1717

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/VarExporter/CHANGELOG.md
+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
CHANGELOG
22
=========
33

4+
7.3
5+
---
6+
7+
* Deprecate using `ProxyHelper::generateLazyProxy()` when native lazy proxies can be used - the method should be used to generate abstraction-based lazy decorators only
8+
* Deprecate `LazyGhostTrait` and `LazyProxyTrait`, use native lazy objects instead
9+
* Deprecate `ProxyHelper::generateLazyGhost()`, use native lazy objects instead
10+
411
7.2
512
---
613

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.