8000 [DependencyInjection][VarExporter] Generate lazy proxies for non-ghos… · symfony/symfony@0074ef4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0074ef4

Browse files
[DependencyInjection][VarExporter] Generate lazy proxies for non-ghostable lazy services out of the box
1 parent e1581a0 commit 0074ef4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

50 files changed

+1769
-515
lines changed

.github/expected-missing-return-types.diff

+23-23
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ head=$(sed '/^diff /Q' .github/expected-missing-return-types.diff)
77
git checkout composer.json src/
88

99
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
10-
index 165797504b..0c0922088a 100644
10+
index 18b5c21b9f..8fca8244e3 100644
1111
--- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
1212
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
13-
@@ -87,5 +87,5 @@ abstract class KernelTestCase extends TestCase
13+
@@ -88,5 +88,5 @@ abstract class KernelTestCase extends TestCase
1414
* @return Container
1515
*/
1616
- protected static function getContainer(): ContainerInterface
@@ -156,52 +156,52 @@ index 6b1c6c5fbe..bb80ed461e 100644
156156
+ public function isFresh(ResourceInterface $resource, int $timestamp): bool;
157157
}
158158
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
159-
index 64068fcc23..f29aaf1b94 100644
159+
index 53f2021fa9..cf95c1fe99 100644
160160
--- a/src/Symfony/Component/Console/Application.php
161161
+++ b/src/Symfony/Component/Console/Application.php
162-
@@ -218,5 +218,5 @@ class Application implements ResetInterface
162+
@@ -219,5 +219,5 @@ class Application implements ResetInterface
163163
* @return int 0 if everything went fine, or an error code
164164
*/
165165
- public function doRun(InputInterface $input, OutputInterface $output)
166166
+ public function doRun(InputInterface $input, OutputInterface $output): int
167167
{
168168
if (true === $input->hasParameterOption(['--version', '-V'], true)) {
169-
@@ -454,5 +454,5 @@ class Application implements ResetInterface
169+
@@ -453,5 +453,5 @@ class Application implements ResetInterface
170170
* @return string
171171
*/
172172
- public function getLongVersion()
173173
+ public function getLongVersion(): string
174174
{
175175
if ('UNKNOWN' !== $this->getName()) {
176-
@@ -497,5 +497,5 @@ class Application implements ResetInterface
176+
@@ -496,5 +496,5 @@ class Application implements ResetInterface
177177
* @return Command|null
178178
*/
179179
- public function add(Command $command)
180180
+ public function add(Command $command): ?Command
181181
{
182182
$this->init();
183-
@@ -534,5 +534,5 @@ class Application implements ResetInterface
183+
@@ -533,5 +533,5 @@ class Application implements ResetInterface
184184
* @throws CommandNotFoundException When given command name does not exist
185185
*/
186186
- public function get(string $name)
187187
+ public function get(string $name): Command
188188
{
189189
$this->init();
190-
@@ -641,5 +641,5 @@ class Application implements ResetInterface
190+
@@ -640,5 +640,5 @@ class Application implements ResetInterface
191191
* @throws CommandNotFoundException When command name is incorrect or ambiguous
192192
*/
193193
- public function find(string $name)
194194
+ public function find(string $name): Command
195195
{
196196
$this->init();
197-
@@ -751,5 +751,5 @@ class Application implements ResetInterface
197+
@@ -750,5 +750,5 @@ class Application implements ResetInterface
198198
* @return Command[]
199199
*/
200200
- public function all(string $namespace = null)
201201
+ public function all(string $namespace = null): array
202202
{
203203
$this->init();
204-
@@ -950,5 +950,5 @@ class Application implements ResetInterface
204+
@@ -949,5 +949,5 @@ class Application implements ResetInterface
205205
* @return int 0 if everything went fine, or an error code
206206
*/
207207
- protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
@@ -234,7 +234,7 @@ index b41e691537..34de10fa70 100644
234234
{
235235
if (null === $this->helperSet) {
236236
diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php
237-
index 3c6b0efccd..121664f15a 100644
237+
index 0112350a50..dc972564fb 100644
238238
--- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php
239239
+++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php
240240
@@ -137,5 +137,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
@@ -301,22 +301,22 @@ index 2f1631ed30..a4b572771e 100644
301301
{
302302
if (\is_array($value)) {
303303
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
304-
index 04b7022484..5d736ec754 100644
304+
index 20ca68e514..e0850df0f8 100644
305305
--- a/src/Symfony/Component/DependencyInjection/Container.php
306306
+++ b/src/Symfony/Component/DependencyInjection/Container.php
307-
@@ -108,5 +108,5 @@ class Container implements ContainerInterface, ResetInterface
308-
* @throws InvalidArgumentException if the parameter is not defined
307+
@@ -109,5 +109,5 @@ class Container implements ContainerInterface, ResetInterface
308+
* @throws ParameterNotFoundException if the parameter is not defined
309309
*/
310310
- public function getParameter(string $name)
311311
+ public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
312312
{
313313
return $this->parameterBag->get($name);
314314
diff --git a/src/Symfony/Component/DependencyInjection/ContainerInterface.php b/src/Symfony/Component/DependencyInjection/ContainerInterface.php
315-
index cad44026c0..14cd192e07 100644
315+
index 9e97fb71fc..1cda97c611 100644
316316
--- a/src/Symfony/Component/DependencyInjection/ContainerInterface.php
317317
+++ b/src/Symfony/Component/DependencyInjection/ContainerInterface.php
318318
@@ -53,5 +53,5 @@ interface ContainerInterface extends PsrContainerInterface
319-
* @throws InvalidArgumentException if the parameter is not defined
319+
* @throws ParameterNotFoundException if the parameter is not defined
320320
*/
321321
- public function getParameter(string $name);
322322
+ public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null;
@@ -358,7 +358,7 @@ index d553203c43..1163f4b107 100644
358358
{
359359
$class = static::class;
360360
diff --git a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
361-
index 4f66f18073..e96d867296 100644
361+
index 11cda00cc5..07b4990160 100644
362362
--- a/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
363363
+++ b/src/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php
364364
@@ -35,5 +35,5 @@ interface ExtensionInterface
@@ -913,7 +913,7 @@ index 5014b9bd51..757c76f546 100644
913913
+ public function supportsDecoding(string $format /* , array $context = [] */): bool;
914914
}
915915
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
916-
index 391cdcb39c..f637687e74 100644
916+
index e426d87076..350cbc6335 100644
917917
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
918918
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
919919
@@ -213,5 +213,5 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
@@ -1094,11 +1094,11 @@ index b22d6ae609..31d1a25f9d 100644
10941094
+ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic): array
10951095
{
10961096
$refs = $values;
1097-
diff --git a/src/Symfony/Component/VarExporter/Internal/GhostObjectState.php b/src/Symfony/Component/VarExporter/Internal/GhostObjectState.php
1098-
index 471c1a6b91..2e19d2ab2d 100644
1099-
--- a/src/Symfony/Component/VarExporter/Internal/GhostObjectState.php
1100-
+++ b/src/Symfony/Component/VarExporter/Internal/GhostObjectState.php
1101-
@@ -54,5 +54,5 @@ class GhostObjectState
1097+
diff --git a/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php b/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php
1098+
index 6ea89bc831..01748bcfc0 100644
1099+
--- a/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php
1100+
+++ b/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php
1101+
@@ -56,5 +56,5 @@ class LazyObjectState
11021102
* @return bool Returns true when fully-initializing, false when partial-initializing
11031103
*/
11041104
- public function initialize($instance, $propertyName, $propertyScope)

src/Symfony/Bridge/Doctrine/ManagerRegistry.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use ProxyManager\Proxy\GhostObjectInterface;
1616
use ProxyManager\Proxy\LazyLoadingInterface;
1717
use Symfony\Component\DependencyInjection\Container;
18-
use Symfony\Component\VarExporter\LazyGhostObjectInterface;
18+
use Symfony\Component\VarExporter\LazyObjectInterface;
1919

2020
/**
2121
* References Doctrine connections and entity/document managers.
@@ -47,8 +47,8 @@ protected function resetService($name): void
4747
}
4848
$manager = $this->container->get($name);
4949

50-
if ($manager instanceof LazyGhostObjectInterface) {
51-
if (!$manager->resetLazyGhostObject()) {
50+
if ($manager instanceof LazyObjectInterface) {
51+
if (!$manager->resetLazyObject()) {
5252
throw new \LogicException(sprintf('Resetting a non-lazy manager service is not supported. Declare the "%s" service as lazy.', $name));
5353
}
5454

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

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PHPUnit\Framework\TestCase;
1717
use ProxyManager\Proxy\LazyLoadingInterface;
1818
use ProxyManagerBridgeFooClass;
19+
use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
1920
use Symfony\Component\DependencyInjection\ContainerBuilder;
2021

2122
/**
@@ -29,6 +30,7 @@ class ContainerBuilderTest extends TestCase
2930
public function testCreateProxyServiceWithRuntimeInstantiator()
3031
{
3132
$builder = new ContainerBuilder();
33+
$builder->setProxyInstantiator(new RuntimeInstantiator());
3234

3335
$builder->register('foo1', ProxyManagerBridgeFooClass::class)->setFile(__DIR__.'/Fixtures/includes/foo.php')->setPublic(true);
3436
$builder->getDefinition('foo1')->setLazy(true)->addTag('proxy', ['interface' => ProxyManagerBridgeFooClass::class]);

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

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use ProxyManager\Proxy\LazyLoadingInterface;
16+
use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
1819

@@ -66,6 +67,7 @@ private function dumpLazyServiceProjectServiceContainer()
6667
$container->compile();
6768

6869
$dumper = new PhpDumper($container);
70+
$dumper->setProxyDumper(new ProxyDumper());
6971

7072
return $dumper->dump(['class' => 'LazyServiceProjectServiceContainer']);
7173
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CHANGELOG
44
6.2
55
---
66

7-
* Use lazy-loading ghost object proxies out of the box
7+
* Use lazy-loading ghost objects and virtual proxies out of the box
88
* Add argument `&$asGhostObject` to LazyProxy's `DumperInterface` to allow using ghost objects for lazy loading services
99
* Add `enum` env var processor
1010
* Add `shuffle` env var processor

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
use Symfony\Component\DependencyInjection\Definition;
2525
use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException;
2626
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
27-
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
2827
use Symfony\Component\DependencyInjection\Reference;
2928
use Symfony\Component\DependencyInjection\TypedReference;
29+
use Symfony\Component\VarExporter\ProxyHelper;
3030
use Symfony\Contracts\Service\Attribute\SubscribedService;
3131

3232
/**
@@ -282,7 +282,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
282282
continue;
283283
}
284284

285-
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
285+
$type = ProxyHelper::exportType($reflectionMethod, $parameter, true);
286286

287287
if ($checkAttributes) {
288288
foreach ($parameter->getAttributes() as $attribute) {
@@ -312,8 +312,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
312312
--$index;
313313
break;
314314
}
315-
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
316-
$type = $type ? sprintf('is type-hinted "%s"', ltrim($type, '\\')) : 'has no type-hint';
315+
$type = ProxyHelper::exportType($reflectionMethod, $parameter);
316+
$type = $type ? sprintf('is type-hinted "%s"', preg_replace('/(^|[(|&])\\\\|^\?\\\\?/', '\1', $type)) : 'has no type-hint';
317317

318318
throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type));
319319
}

src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
use Symfony\Component\DependencyInjection\Definition;
2020
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
2121
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
22-
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
2322
use Symfony\Component\DependencyInjection\Reference;
2423
use Symfony\Component\DependencyInjection\TypedReference;
24+
use Symfony\Component\VarExporter\ProxyHelper;
2525

2626
/**
2727
* @author Guilhem Niot <guilhem.niot@gmail.com>
@@ -182,10 +182,11 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
182182
continue;
183183
}
184184

185-
$typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter);
185+
$typeHint = ltrim(ProxyHelper::exportType($reflectionMethod, $parameter) ?? '', '?');
186+
186187
$name = Target::parseName($parameter);
187188

188-
if ($typeHint && \array_key_exists($k = ltrim($typeHint, '\\').' $'.$name, $bindings)) {
189+
if ($typeHint && \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$name, $bindings)) {
189190
$arguments[$key] = $this->getBindingValue($bindings[$k]);
190191

191192
continue;

src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
1515
use Symfony\Component\DependencyInjection\Definition;
1616
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
17-
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
1817
use Symfony\Component\DependencyInjection\Reference;
18+
use Symfony\Component\VarExporter\ProxyHelper;
1919

2020
/**
2121
* Resolves named arguments to their corresponding numeric index.
@@ -90,7 +90,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
9090

9191
$typeFound = false;
9292
foreach ($parameters as $j => $p) {
93-
if (!\array_key_exists($j, $resolvedArguments) && ProxyHelper::getTypeHint($r, $p, true) === $key) {
93+
if (!\array_key_exists($j, $resolvedArguments) && ProxyHelper::exportType($r, $p, true) === $key) {
9494
$resolvedArguments[$j] = $argument;
9595
$typeFound = true;
9696
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
4747
use Symfony\Component\ExpressionLanguage\Expression;
4848
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
49-
use Symfony\Component\VarExporter\Hydrator;
5049

5150
/**
5251
* ContainerBuilder is a DI container that provides an API to easily describe services.
@@ -1040,10 +1039,6 @@ private function createService(Definition $definition, array &$inlineServices, b
10401039
if (null !== $factory) {
10411040
$service = $factory(...$arguments);
10421041

1043-
if (\is_object($tryProxy) && \get_class($service) !== $parameterBag->resolveValue($definition->getClass())) {
1044-
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1$s".', $definition->getClass(), get_debug_type($service)));
1045-
}
1046-
10471042
if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
10481043
$r = new \ReflectionClass($factory[0]);
10491044

@@ -1113,10 +1108,6 @@ private function createService(Definition $definition, array &$inlineServices, b
11131108
$callable($service);
11141109
}
11151110

1116-
if (\is_object($tryProxy) && $tryProxy !== $service) {
1117-
return Hydrator::hydrate($tryProxy, (array) $service);
1118-
}
1119-
11201111
return $service;
11211112
}
11221113

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

+2-24
Original file line numberDiff line numberDiff line change
@@ -676,9 +676,6 @@ private function addServiceInstance(string $id, Definition $definition, bool $is
676676

677677
$return = '';
678678
if ($isSimpleInstance) {
679-
if ($asGhostObject && null !== $definition->getFactory()) {
680-
$instantiation .= '$this->hydrateProxy($lazyLoad, ';
681-
}
682679
$return = 'return ';
683680
} else {
684681
$instantiation .= ' = ';
@@ -896,9 +893,7 @@ protected function {$methodName}($lazyInitialization)
896893
$code .= sprintf(' %s ??= ', $factory);
897894

898895
if ($asFile) {
899-
$code .= "function () {\n";
900-
$code .= " return self::do(\$container);\n";
901-
$code .= " };\n\n";
896+
$code .= "fn () => self::do(\$container);\n\n";
902897
} else {
903898
$code .= sprintf("\$this->%s(...);\n\n", $methodName);
904899
}
@@ -1079,11 +1074,7 @@ private function addInlineService(string $id, Definition $definition, Definition
10791074
return $code;
10801075
}
10811076

1082-
if (!$asGhostObject) {
1083-
return $code."\n return \$instance;\n";
1084-
}
1085-
1086-
return $code."\n return \$this->hydrateProxy(\$lazyLoad, \$instance);\n";
1077+
return $code."\n return \$instance;\n";
10871078
}
10881079

10891080
private function addServices(array &$services = null): string
@@ -1329,19 +1320,6 @@ protected function createProxy(\$class, \Closure \$factory)
13291320
{$proxyLoader}return \$factory();
13301321
}
13311322
1332-
protected function hydrateProxy(\$proxy, \$instance)
1333-
{
1334-
if (\$proxy === \$instance) {
1335-
return \$proxy;
1336-
}
1337-
1338-
if (!\in_array(\get_class(\$instance), [\get_class(\$proxy), get_parent_class(\$proxy)], true)) {
1339-
throw new LogicException(sprintf('Lazy service of type "%s" cannot be hydrated because its factory returned an unexpected instance of "%s". Try adding the "proxy" tag to the corresponding service definition with attribute "interface" set to "%1\$s".', get_parent_class(\$proxy), get_debug_type(\$instance)));
1340-
}
1341-
1342-
return \Symfony\Component\VarExporter\Hydrator::hydrate(\$proxy, (array) \$instance);
1343-
}
1344-
13451323
EOF;
13461324
break;
13471325
}

src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/LazyServiceInstantiator.php

+4-10
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@
1111

1212
namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator;
1313

14-
use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
1514
use Symfony\Component\DependencyInjection\ContainerInterface;
1615
use Symfony\Component\DependencyInjection\Definition;
1716
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper;
18-
use Symfony\Component\VarExporter\LazyGhostObjectInterface;
19-
use Symfony\Component\VarExporter\LazyGhostObjectTrait;
17+
use Symfony\Component\VarExporter\LazyGhostTrait;
2018

2119
/**
2220
* @author Nicolas Grekas <p@tchwork.com>
@@ -30,14 +28,10 @@ public function instantiateProxy(ContainerInterface $container, Definition $defi
3028
{
3129
$dumper = new LazyServiceDumper();
3230

33-
if ($dumper->useProxyManager($definition)) {
34-
return (new RuntimeInstantiator())->instantiateProxy($container, $definition, $id, $realInstantiator);
31+
if (!class_exists($proxyClass = $dumper->getProxyClass($definition, $class), false)) {
32+
eval($dumper->getProxyCode($definition));
3533
}
3634

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);
35+
return isset(class_uses($proxyClass)[LazyGhostTrait::class]) ? $proxyClass::createLazyGhost($realInstantiator) : $proxyClass::createLazyProxy($realInstantiator);
4236
}
4337
}

0 commit comments

Comments
 (0)
0