Skip to content

Commit 074b9b7

Browse files
[Serializer] Generalize caching support a bit
1 parent c1e850f commit 074b9b7

12 files changed

+73
-60
lines changed

src/Symfony/Component/Serializer/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
4.1.0
55
-----
66

7+
* added `CacheableSupportsMethodInterface` for normalizers and denormalizers that use
8+
only the type and the format in their `supports*()` methods
79
* added `MissingConstructorArgumentsException` new exception for deserialization failure
810
of objects that needs data insertion in constructor
911
* added an optional `default_constructor_arguments` option of context to specify a default data in

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

+2-7
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@
3030
*
3131
* @author Kévin Dunglas <dunglas@gmail.com>
3232
*/
33-
abstract class AbstractObjectNormalizer extends AbstractNormalizer implements NormalizerWithCacheableSupportResultInterface
33+
abstract class AbstractObjectNormalizer extends AbstractNormalizer implements CacheableSupportsMethodInterface
3434
{
3535
const ENABLE_MAX_DEPTH = 'enable_max_depth';
3636
const DEPTH_KEY_PATTERN = 'depth_%s::%s';
3737
const DISABLE_TYPE_ENFORCEMENT = 'disable_type_enforcement';
3838

3939
private $propertyTypeExtractor;
4040
private $attributesCache = array();
41-
private $cache = array();
4241

4342
/**
4443
* @var callable|null
@@ -225,11 +224,7 @@ public function setMaxDepthHandler(?callable $handler): void
225224
*/
226225
public function supportsDenormalization($data, $type, $format = null)
227226
{
228-
if (!isset($this->cache[$type])) {
229-
$this->cache[$type] = class_exists($type) || (interface_exists($type) && null !== $this->classDiscriminatorResolver && null !== $this->classDiscriminatorResolver->getMappingForClass($type));
230-
}
231-
232-
return $this->cache[$type];
227+
return \class_exists($type) || (\interface_exists($type, false) && $this->classDiscriminatorResolver && null !== $this->classDiscriminatorResolver->getMappingForClass($type));
233228
}
234229

235230
/**
+6-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
namespace Symfony\Component\Serializer\Normalizer;
1313

1414
/**
15-
* "supportsNormalization()" methods of normalizers implementing this interface have a cacheable return.
15+
* Marker interface for normalizers and denormalizers that use
16+
* only the type and the format in their supports*() methods.
17+
*
18+
* By implementing this interface, the return value of the
19+
* supports*() methods will be cached by type and format.
1620
*
1721
* @author Kévin Dunglas <dunglas@gmail.com>
1822
*/
19-
interface NormalizerWithCacheableSupportResultInterface
23+
interface CacheableSupportsMethodInterface
2024
{
2125
}

src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @author Grégoire Pineau <lyrixx@lyrixx.info>
2323
* @author Kévin Dunglas <dunglas@gmail.com>
2424
*/
25-
class ConstraintViolationListNormalizer implements NormalizerInterface, NormalizerWithCacheableSupportResultInterface
25+
class ConstraintViolationListNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface
2626
{
2727
/**
2828
* {@inheritdoc}

src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php

+2-12
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
/**
1818
* @author Jordi Boggiano <j.boggiano@seld.be>
1919
*/
20-
class CustomNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, NormalizerWithCacheableSupportResultInterface
20+
class CustomNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
2121
{
2222
use ObjectToPopulateTrait;
2323
use SerializerAwareTrait;
2424

25-
private $cache = array();
26-
2725
/**
2826
* {@inheritdoc}
2927
*/
@@ -67,14 +65,6 @@ public function supportsNormalization($data, $format = null)
6765
*/
6866
public function supportsDenormalization($data, $type, $format = null)
6967
{
70-
if (isset($this->cache[$type])) {
71-
return $this->cache[$type];
72-
}
73-
74-
if (!class_exists($type)) {
75-
return $this->cache[$type] = false;
76-
}
77-
78-
return $this->cache[$type] = is_subclass_of($type, 'Symfony\Component\Serializer\Normalizer\DenormalizableInterface');
68+
return \is_subclass_of($type, DenormalizableInterface::class);
7969
}
8070
}

src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*
2424
* @author Kévin Dunglas <dunglas@gmail.com>
2525
*/
26-
class DataUriNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerWithCacheableSupportResultInterface
26+
class DataUriNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
2727
{
2828
private static $supportedTypes = array(
2929
\SplFileInfo::class => true,

src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*
2121
* @author Jérôme Parmentier <jerome@prmntr.me>
2222
*/
23-
class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerWithCacheableSupportResultInterface
23+
class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
2424
{
2525
const FORMAT_KEY = 'dateinterval_format';
2626

src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*
2121
* @author Kévin Dunglas <dunglas@gmail.com>
2222
*/
23-
class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerWithCacheableSupportResultInterface
23+
class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
2424
{
2525
const FORMAT_KEY = 'datetime_format';
2626
const TIMEZONE_KEY = 'datetime_timezone';

src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,21 @@
3535
class GetSetMethodNormalizer extends AbstractObjectNormalizer
3636
{
3737
private static $setterAccessibleCache = array();
38-
private $cache = array();
3938

4039
/**
4140
* {@inheritdoc}
4241
*/
4342
public function supportsNormalization($data, $format = null)
4443
{
45-
return parent::supportsNormalization($data, $format) && (isset($this->cache[$type = \get_class($data)]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
44+
return parent::supportsNormalization($data, $format) && $this->supports(\get_class($data));
4645
}
4746

4847
/**
4948
* {@inheritdoc}
5049
*/
5150
public function supportsDenormalization($data, $type, $format = null)
5251
{
53-
return parent::supportsDenormalization($data, $type, $format) && (isset($this->cache[$type]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
52+
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
5453
}
5554

5655
/**

src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
* @author Fred Cox <mcfedr@gmail.com>
2121
*/
22-
class JsonSerializableNormalizer extends AbstractNormalizer implements NormalizerWithCacheableSupportResultInterface
22+
class JsonSerializableNormalizer extends AbstractNormalizer implements CacheableSupportsMethodInterface
2323
{
2424
/**
2525
* {@inheritdoc}

src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,20 @@
3030
*/
3131
class PropertyNormalizer extends AbstractObjectNormalizer
3232
{
33-
private $cache = array();
34-
3533
/**
3634
* {@inheritdoc}
3735
*/
3836
public function supportsNormalization($data, $format = null)
3937
{
40-
return parent::supportsNormalization($data, $format) && (isset($this->cache[$type = \get_class($data)]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
38+
return parent::supportsNormalization($data, $format) && $this->supports(\get_class($data));
4139
}
4240

4341
/**
4442
* {@inheritdoc}
4543
*/
4644
public function supportsDenormalization($data, $type, $format = null)
4745
{
48-
return parent::supportsDenormalization($data, $type, $format) && (isset($this->cache[$type]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
46+
return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
4947
}
5048

5149
/**

src/Symfony/Component/Serializer/Serializer.php

+52-27
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2727
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
2828
use Symfony\Component\Serializer\Exception\LogicException;
29-
use Symfony\Component\Serializer\Normalizer\NormalizerWithCacheableSupportResultInterface;
29+
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
3030

3131
/**
3232
* Serializer serializes and deserializes data.
@@ -55,13 +55,15 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface
5555
*/
5656
protected $decoder;
5757

58-
private $normalizerCache = array();
59-
6058
/**
61-
* @var array
59+
* @internal since Symfony 4.1
6260
*/
6361
protected $normalizers = array();
6462

63+
private $cachedNormalizers;
64+
private $denormalizerCache = array();
65+
private $normalizerCache = array();
66+
6567
public function __construct(array $normalizers = array(), array $encoders = array())
6668
{
6769
foreach ($normalizers as $normalizer) {
@@ -203,35 +205,36 @@ public function supportsDenormalization($data, $type, $format = null, array $con
203205
*
204206
* @return NormalizerInterface|null
205207
*/
206-
private function getNormalizer($data, $format, array $context)
208+
private function getNormalizer($data, ?string $format, array $context)
207209
{
208-
$type = \is_object($data) ? 'c-'.\get_class($data) : \gettype($data);
209-
if (
210-
isset($this->normalizerCache[$type][$format]) ||
211-
(isset($this->normalizerCache[$type]) && \array_key_exists($format, $this->normalizerCache[$type]))
212-
) {
213-
return $this->normalizerCache[$type][$format];
210+
if ($this->cachedNormalizers !== $this->normalizers) {
211+
$this->cachedNormalizers = $this->normalizers;
212+
$this->denormalizerCache = $this->normalizerCache = array();
214213
}
214+
$type = \is_object($data) ? \get_class($data) : 'native-'.\gettype($data);
215215

216-
$cacheable = true;
217-
foreach ($this->normalizers as $normalizer) {
218-
if (!$normalizer instanceof NormalizerInterface) {
219-
continue;
220-
}
216+
if (!isset($this->normalizerCache[$format][$type])) {
217+
$this->normalizerCache[$format][$type] = array();
221218

222-
$cacheable = $cacheable && $normalizer instanceof NormalizerWithCacheableSupportResultInterface;
223-
if ($normalizer->supportsNormalization($data, $format, $context)) {
224-
if ($cacheable) {
225-
$this->normalizerCache[$type][$format] = $normalizer;
219+
foreach ($this->normalizers as $k => $normalizer) {
220+
if (!$normalizer instanceof NormalizerInterface) {
221+
continue;
226222
}
227223

228-
return $normalizer;
224+
if (!$normalizer instanceof CacheableSupportsMethodInterface) {
225+
$this->normalizerCache[$format][$type][$k] = false;
226+
} elseif ($normalizer->supportsNormalization($data, $format)) {
227+
$this->normalizerCache[$format][$type][$k] = true;
228+
break;
229+
}
229230
}
230231
}
231232

232-
if ($cacheable) {
233-
// allow to cache primitive types
234-
$this->normalizerCache[$type][$format] = null;
233+
foreach ($this->normalizerCache[$format][$type] as $k => $cacheable) {
234+
$normalizer = $this->normalizers[$k];
235+
if ($cacheable || $normalizer->supportsNormalization($data, $format, $context)) {
236+
return $normalizer;
237+
}
235238
}
236239
}
237240

@@ -245,10 +248,32 @@ private function getNormalizer($data, $format, array $context)
245248
*
246249
* @return DenormalizerInterface|null
247250
*/
248-
private function getDenormalizer($data, $class, $format, array $context)
251+
private function getDenormalizer($data, string $class, ?string $format, array $context)
249252
{
250-
foreach ($this->normalizers as $normalizer) {
251-
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format, $context)) {
253+
if ($this->cachedNormalizers !== $this->normalizers) {
254+
$this->cachedNormalizers = $this->normalizers;
255+
$this->denormalizerCache = $this->normalizerCache = array();
256+
}
257+
if (!isset($this->denormalizerCache[$format][$class])) {
258+
$this->denormalizerCache[$format][$class] = array();
259+
260+
foreach ($this->normalizers as $k => $normalizer) {
261+
if (!$normalizer instanceof DenormalizerInterface) {
262+
continue;
263+
}
264+
265+
if (!$normalizer instanceof CacheableSupportsMethodInterface) {
266+
$this->denormalizerCache[$format][$class][$k] = false;
267+
} elseif ($normalizer->supportsDenormalization(null, $class, $format)) {
268+
$this->denormalizerCache[$format][$class][$k] = true;
269+
break;
270+
}
271+
}
272+
}
273+
274+
foreach ($this->denormalizerCache[$format][$class] as $k => $cacheable) {
275+
$normalizer = $this->normalizers[$k];
276+
if ($cacheable || $normalizer->supportsDenormalization($data, $class, $format, $context)) {
252277
return $normalizer;
253278
}
254279
}

0 commit comments

Comments
 (0)