From ffccbc3e342efec0d90849ed0141423ea4c29b09 Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Wed, 11 Dec 2024 13:35:15 +0100 Subject: [PATCH] [JsonEncoder] Add native lazyghost support --- .../FrameworkExtension.php | 4 ++ .../Component/JsonEncoder/CHANGELOG.md | 1 + .../JsonEncoder/Decode/LazyInstantiator.php | 33 +++++---- .../JsonEncoder/Decode/PhpAstBuilder.php | 49 +++++++------ .../JsonEncoder/Encode/PhpAstBuilder.php | 2 +- .../GenericTypePropertyMetadataLoader.php | 2 +- .../Tests/Decode/LazyInstantiatorTest.php | 38 ++++++++-- .../decoder/nullable_object.stream.php | 22 +++--- .../decoder/nullable_object_dict.stream.php | 22 +++--- .../decoder/nullable_object_list.stream.php | 22 +++--- .../Tests/Fixtures/decoder/object.stream.php | 22 +++--- .../Fixtures/decoder/object_dict.stream.php | 22 +++--- .../decoder/object_in_object.stream.php | 70 ++++++++----------- .../Fixtures/decoder/object_list.stream.php | 22 +++--- .../object_with_denormalizer.stream.php | 30 +++----- ...object_with_nullable_properties.stream.php | 22 +++--- .../decoder/object_with_union.stream.php | 18 +++-- .../Tests/Fixtures/decoder/union.stream.php | 22 +++--- 18 files changed, 202 insertions(+), 221 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 862abe3ca5942..d911b767db7ac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2032,6 +2032,10 @@ private function registerJsonEncoderConfiguration(array $config, ContainerBuilde foreach ($config['paths'] as $namespace => $path) { $loader->registerClasses($encodableDefinition, $namespace, $path); } + + if (\PHP_VERSION_ID >= 80400) { + $container->removeDefinition('.json_encoder.cache_warmer.lazy_ghost'); + } } private function registerPropertyInfoConfiguration(ContainerBuilder $container, PhpFileLoader $loader): void diff --git a/src/Symfony/Component/JsonEncoder/CHANGELOG.md b/src/Symfony/Component/JsonEncoder/CHANGELOG.md index 5294c5b5f3637..327d5f6cec3ef 100644 --- a/src/Symfony/Component/JsonEncoder/CHANGELOG.md +++ b/src/Symfony/Component/JsonEncoder/CHANGELOG.md @@ -5,3 +5,4 @@ CHANGELOG --- * Introduce the component as experimental + * Add native PHP lazy ghost support diff --git a/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php b/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php index 8904bc455bd3d..285793c75bd4f 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php +++ b/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php @@ -12,15 +12,15 @@ namespace Symfony\Component\JsonEncoder\Decode; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; use Symfony\Component\JsonEncoder\Exception\RuntimeException; use Symfony\Component\VarExporter\ProxyHelper; /** * Instantiates a new $className lazy ghost {@see \Symfony\Component\VarExporter\LazyGhostTrait}. * - * The $className class must not be final. - * - * A property must be a callable that returns the actual value when being called. + * Prior to PHP 8.4, the "$className" argument class must not be final. + * The $initializer must be a callable that sets the actual object values when being called. * * @author Mathias Arlaud * @@ -28,7 +28,7 @@ */ final class LazyInstantiator { - private Filesystem $fs; + private ?Filesystem $fs = null; /** * @var array{reflection: array>, lazy_class_name: array} @@ -44,20 +44,22 @@ final class LazyInstantiator private static array $lazyClassesLoaded = []; public function __construct( - private string $lazyGhostsDir, + private ?string $lazyGhostsDir = null, ) { - $this->fs = new Filesystem(); + if (null === $this->lazyGhostsDir && \PHP_VERSION_ID < 80400) { + throw new InvalidArgumentException('The "$lazyGhostsDir" argument cannot be null when using PHP < 8.4.'); + } } /** * @template T of object * - * @param class-string $className - * @param array $propertiesCallables + * @param class-string $className + * @param callable(T): void $initializer * * @return T */ - public function instantiate(string $className, array $propertiesCallables): object + public function instantiate(string $className, callable $initializer): object { try { $classReflection = self::$cache['reflection'][$className] ??= new \ReflectionClass($className); @@ -65,13 +67,14 @@ public function instantiate(string $className, array $propertiesCallables): obje throw new RuntimeException($e->getMessage(), $e->getCode(), $e); } - $lazyClassName = self::$cache['lazy_class_name'][$className] ??= \sprintf('%sGhost', preg_replace('/\\\\/', '', $className)); + // use native lazy ghosts if available + if (\PHP_VERSION_ID >= 80400) { + return $classReflection->newLazyGhost($initializer); + } - $initializer = function (object $object) use ($propertiesCallables) { - foreach ($propertiesCallables as $name => $propertyCallable) { - $object->{$name} = $propertyCallable(); - } - }; + $this->fs ??= new Filesystem(); + + $lazyClassName = self::$cache['lazy_class_name'][$className] ??= \sprintf('%sGhost', preg_replace('/\\\\/', '', $className)); if (isset(self::$lazyClassesLoaded[$className]) && class_exists($lazyClassName)) { return $lazyClassName::createLazyGhost($initializer); diff --git a/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php b/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php index 3ade6a5de4d53..1a445a9554c5c 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php +++ b/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php @@ -53,8 +53,8 @@ use Symfony\Component\TypeInfo\Type\BackedEnumType; use Symfony\Component\TypeInfo\Type\CollectionType; use Symfony\Component\TypeInfo\Type\ObjectType; -use Symfony\Component\TypeInfo\TypeIdentifier; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; +use Symfony\Component\TypeInfo\TypeIdentifier; /** * Builds a PHP syntax tree that decodes JSON. @@ -445,21 +445,8 @@ private function buildObjectNodeStatements(ObjectNode $node, bool $decodeFromStr ); $streamPropertiesValuesStmts[] = new MatchArm([$this->builder->val($encodedName)], new Assign( - new ArrayDimFetch($this->builder->var('properties'), $this->builder->val($property['name'])), - new Closure([ - 'static' => true, - 'uses' => [ - new ClosureUse($this->builder->var('stream')), - new ClosureUse($this->builder->var('v')), - new ClosureUse($this->builder->var('options')), - new ClosureUse($this->builder->var('denormalizers')), - new ClosureUse($this->builder->var('instantiator')), - new ClosureUse($this->builder->var('providers'), byRef: true), - ], - 'stmts' => [ - new Return_($property['accessor'](new PhpExprDataAccessor($propertyValueStmt))->toPhpExpr()), - ], - ]), + $this->builder->propertyFetch($this->builder->var('object'), $property['name']), + $property['accessor'](new PhpExprDataAccessor($propertyValueStmt))->toPhpExpr(), )); } else { $propertyValueStmt = $this->nodeOnlyNeedsDecode($property['value'], $decodeFromStream) @@ -494,17 +481,29 @@ private function buildObjectNodeStatements(ObjectNode $node, bool $decodeFromStr if ($decodeFromStream) { $instantiateStmts = [ - new Expression(new Assign($this->builder->var('properties'), new Array_([], ['kind' => Array_::KIND_SHORT]))), - new Foreach_($this->builder->var('data'), $this->builder->var('v'), [ - 'keyVar' => $this->builder->var('k'), - 'stmts' => [new Expression(new Match_( - $this->builder->var('k'), - [...$streamPropertiesValuesStmts, new MatchArm(null, $this->builder->val(null))], - ))], - ]), new Return_($this->builder->methodCall($this->builder->var('instantiator'), 'instantiate', [ new ClassConstFetch(new FullyQualified($node->getType()->getClassName()), 'class'), - $this->builder->var('properties'), + new Closure([ + 'static' => true, + 'params' => [new Param($this->builder->var('object'))], + 'uses' => [ + new ClosureUse($this->builder->var('stream')), + new ClosureUse($this->builder->var('data')), + new ClosureUse($this->builder->var('options')), + new ClosureUse($this->builder->var('denormalizers')), + new ClosureUse($this->builder->var('instantiator')), + new ClosureUse($this->builder->var('providers'), byRef: true), + ], + 'stmts' => [ + new Foreach_($this->builder->var('data'), $this->builder->var('v'), [ + 'keyVar' => $this->builder->var('k'), + 'stmts' => [new Expression(new Match_( + $this->builder->var('k'), + [...$streamPropertiesValuesStmts, new MatchArm(null, $this->builder->val(null))], + ))], + ]), + ], + ]), ])), ]; } else { diff --git a/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php b/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php index 20a60ec50baa8..9315c63e633bb 100644 --- a/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php +++ b/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php @@ -45,8 +45,8 @@ use Symfony\Component\JsonEncoder\Exception\RuntimeException; use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; use Symfony\Component\TypeInfo\Type\ObjectType; -use Symfony\Component\TypeInfo\TypeIdentifier; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; +use Symfony\Component\TypeInfo\TypeIdentifier; /** * Builds a PHP syntax tree that encodes data to JSON. diff --git a/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php b/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php index 7ca5749670496..4604e96e1a7ac 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php @@ -18,8 +18,8 @@ use Symfony\Component\TypeInfo\Type\IntersectionType; use Symfony\Component\TypeInfo\Type\ObjectType; use Symfony\Component\TypeInfo\Type\UnionType; -use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; +use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; /** * Enhances properties encoding/decoding metadata based on properties' generic type. diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php b/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php index b040c53f21ad9..926e6d52a048b 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\JsonEncoder\Decode\LazyInstantiator; +use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes; @@ -32,17 +33,46 @@ protected function setUp(): void } } - public function testCreateLazyGhost() + /** + * @requires PHP < 8.4 + */ + public function testCreateLazyGhostUsingVarExporter() { - $ghost = (new LazyInstantiator($this->lazyGhostsDir))->instantiate(ClassicDummy::class, []); + $ghost = (new LazyInstantiator($this->lazyGhostsDir))->instantiate(ClassicDummy::class, function (ClassicDummy $object): void { + $object->id = 123; + }); - $this->assertArrayHasKey(\sprintf("\0%sGhost\0lazyObjectState", preg_replace('/\\\\/', '', ClassicDummy::class)), (array) $ghost); + $this->assertSame(123, $ghost->id); } + /** + * @requires PHP < 8.4 + */ public function testCreateCacheFile() { - (new LazyInstantiator($this->lazyGhostsDir))->instantiate(DummyWithNormalizerAttributes::class, []); + (new LazyInstantiator($this->lazyGhostsDir))->instantiate(DummyWithNormalizerAttributes::class, function (ClassicDummy $object): void {}); $this->assertCount(1, glob($this->lazyGhostsDir.'/*')); } + + /** + * @requires PHP < 8.4 + */ + public function testThrowIfLazyGhostDirNotDefined() + { + $this->expectException(InvalidArgumentException::class); + new LazyInstantiator(); + } + + /** + * @requires PHP 8.4 + */ + public function testCreateLazyGhostUsingPhp() + { + $ghost = (new LazyInstantiator())->instantiate(ClassicDummy::class, function (ClassicDummy $object): void { + $object->id = 123; + }); + + $this->assertSame(123, $ghost->id); + } } diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php index 511c27f1b37e3..a7f614070baad 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php @@ -3,19 +3,15 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php index 94cb55d48913b..0189600e61763 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php @@ -12,19 +12,15 @@ }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php index 4ca2a5b54393b..ac3e4e3a28957 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php @@ -12,19 +12,15 @@ }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php index 8d9e7c9c87b6c..5e7782673a097 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php @@ -3,19 +3,15 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, 0, null); }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php index fcfe59241f5bf..a6da8487c7992 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php @@ -12,19 +12,15 @@ }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; return $providers['array']($stream, 0, null); }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php index 1ba3364db4b67..cbab332a9b1d9 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php @@ -3,54 +3,40 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'otherDummyOne' => $properties['otherDummyOne'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($stream, $v[0], $v[1]); - }, - 'otherDummyTwo' => $properties['otherDummyTwo'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'otherDummyOne' => $object->otherDummyOne = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($stream, $v[0], $v[1]), + 'otherDummyTwo' => $object->otherDummyTwo = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - '@id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + '@id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies']($stream, 0, null); }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php index 3fcbe053e1fe5..22d1d55cbc474 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php @@ -12,19 +12,15 @@ }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; return $providers['array']($stream, 0, null); }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_denormalizer.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_denormalizer.stream.php index b1db54117f06a..f7d97892ab8e0 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_denormalizer.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_denormalizer.stream.php @@ -3,25 +3,17 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $denormalizers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\Denormalizer\DivideStringAndCastToIntDenormalizer')->denormalize(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options); - }, - 'active' => $properties['active'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $denormalizers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\Denormalizer\BooleanStringDenormalizer')->denormalize(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return strtoupper(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1])); - }, - 'range' => $properties['range'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes::explodeRange(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = $denormalizers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\Denormalizer\DivideStringAndCastToIntDenormalizer')->denormalize(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), + 'active' => $object->active = $denormalizers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\Denormalizer\BooleanStringDenormalizer')->denormalize(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), + 'name' => $object->name = strtoupper(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1])), + 'range' => $object->range = Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes::explodeRange(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), + default => null, + }; + } + }); }; return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNormalizerAttributes']($stream, 0, null); }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php index def42f303dab1..3f1aaef7023d3 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php @@ -3,19 +3,15 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'enum' => $properties['enum'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null']($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'enum' => $object->enum = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null']($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length)); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php index 6b2fb975408b2..025751bbb64a8 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php @@ -3,16 +3,14 @@ return static function (mixed $stream, \Psr\Container\ContainerInterface $denormalizers, \Symfony\Component\JsonEncoder\Decode\LazyInstantiator $instantiator, array $options): mixed { $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - 'value' => $properties['value'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'value' => $object->value = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length)); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php index 2505729a456a2..38228a55075d6 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php +++ b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php @@ -15,19 +15,15 @@ }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $properties = []; - foreach ($data as $k => $v) { - match ($k) { - '@id' => $properties['id'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - 'name' => $properties['name'] = static function () use ($stream, $v, $options, $denormalizers, $instantiator, &$providers) { - return \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); - }, - default => null, - }; - } - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, $properties); + return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $denormalizers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + '@id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); }; $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'] = static function ($stream, $offset, $length) use ($options, $denormalizers, $instantiator, &$providers) { $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length);