-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Cache the normalizer to use when possible #27049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Serializer\Normalizer; | ||
|
||
/** | ||
* Marker interface for normalizers and denormalizers that use | ||
* only the type and the format in their supports*() methods. | ||
* | ||
* By implementing this interface, the return value of the | ||
* supports*() methods will be cached by type and format. | ||
* | ||
* @author Kévin Dunglas <dunglas@gmail.com> | ||
*/ | ||
interface CacheableSupportsMethodInterface | ||
{ | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
use Symfony\Component\Serializer\Normalizer\NormalizerInterface; | ||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; | ||
use Symfony\Component\Serializer\Exception\LogicException; | ||
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; | ||
|
||
/** | ||
* Serializer serializes and deserializes data. | ||
|
@@ -55,10 +56,14 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface | |
protected $decoder; | ||
|
||
/** | ||
* @var array | ||
* @internal since Symfony 4.1 | ||
*/ | ||
protected $normalizers = array(); | ||
|
||
private $cachedNormalizers; | ||
private $denormalizerCache = array(); | ||
private $normalizerCache = array(); | ||
|
||
public function __construct(array $normalizers = array(), array $encoders = array()) | ||
{ | ||
foreach ($normalizers as $normalizer) { | ||
|
@@ -200,10 +205,35 @@ public function supportsDenormalization($data, $type, $format = null, array $con | |
* | ||
* @return NormalizerInterface|null | ||
*/ | ||
private function getNormalizer($data, $format, array $context) | ||
private function getNormalizer($data, ?string $format, array $context) | ||
{ | ||
foreach ($this->normalizers as $normalizer) { | ||
if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format, $context)) { | ||
if ($this->cachedNormalizers !== $this->normalizers) { | ||
$this->cachedNormalizers = $this->normalizers; | ||
$this->denormalizerCache = $this->normalizerCache = array(); | ||
} | ||
$type = \is_object($data) ? \get_class($data) : 'native-'.\gettype($data); | ||
|
||
if (!isset($this->normalizerCache[$format][$type])) { | ||
$this->normalizerCache[$format][$type] = array(); | ||
|
||
foreach ($this->normalizers as $k => $normalizer) { | ||
if (!$normalizer instanceof NormalizerInterface) { | ||
continue; | ||
} | ||
|
||
if (!$normalizer instanceof CacheableSupportsMethodInterface) { | ||
$this->normalizerCache[$format][$type][$k] = false; | ||
} elseif ($normalizer->supportsNormalization($data, $format)) { | ||
$this->normalizerCache[$format][$type][$k] = true; | ||
|
||
return $normalizer; | ||
} | ||
} | ||
} | ||
|
||
foreach ($this->normalizerCache[$format][$type] as $k => $cached) { | ||
$normalizer = $this->normalizers[$k]; | ||
if ($cached || $normalizer->supportsNormalization($data, $format, $context)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to clarify maybe you can replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bof, this is a local variable, and the concern is separated by 5 lines... |
||
return $normalizer; | ||
} | ||
} | ||
|
@@ -219,10 +249,33 @@ private function getNormalizer($data, $format, array $context) | |
* | ||
* @return DenormalizerInterface|null | ||
*/ | ||
private function getDenormalizer($data, $class, $format, array $context) | ||
private function getDenormalizer($data, string $class, ?string $format, array $context) | ||
{ | ||
foreach ($this->normalizers as $normalizer) { | ||
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format, $context)) { | ||
if ($this->cachedNormalizers !== $this->normalizers) { | ||
$this->cachedNormalizers = $this->normalizers; | ||
$this->denormalizerCache = $this->normalizerCache = array(); | ||
} | ||
if (!isset($this->denormalizerCache[$format][$class])) { | ||
$this->denormalizerCache[$format][$class] = array(); | ||
|
||
foreach ($this->normalizers as $k => $normalizer) { | ||
if (!$normalizer instanceof DenormalizerInterface) { | ||
continue; | ||
} | ||
|
||
if (!$normalizer instanceof CacheableSupportsMethodInterface) { | ||
$this->denormalizerCache[$format][$class][$k] = false; | ||
} elseif ($normalizer->supportsDenormalization(null, $class, $format)) { | ||
$this->denormalizerCache[$format][$class][$k] = true; | ||
|
||
return $normalizer; | ||
} | ||
} | ||
} | ||
|
||
foreach ($this->denormalizerCache[$format][$class] as $k => $cached) { | ||
$normalizer = $this->normalizers[$k]; | ||
if ($cached || $normalizer->supportsDenormalization($data, $class, $format, $context)) { | ||
return $normalizer; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolas-grekas what is this property for? it it set below but never used again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah,
$this->normalizers
is protected so could be edited by extensions. in which case you'd want to reset the cache?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that's the purpose, allowing efficient caching without breaking BC of the protected property (which is now internal so will be removed in 5.0