From 5c68128030cb431df993eb30fe29e1198c7b0f5b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 14 Aug 2025 15:15:05 +0200 Subject: [PATCH] [Validator] Deprecate implementing `__sleep/wakeup()` on GenericMetadata implementations --- UPGRADE-7.4.md | 1 + .../DataCollector/DataCollector.php | 8 +-- src/Symfony/Component/HttpKernel/Kernel.php | 8 +-- .../Component/String/AbstractString.php | 4 +- src/Symfony/Component/String/LazyString.php | 6 +-- .../Component/String/UnicodeString.php | 4 +- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Validator/Mapping/ClassMetadata.php | 51 ++++++++++++++++--- .../Validator/Mapping/GenericMetadata.php | 34 +++++++++++-- .../Validator/Mapping/MemberMetadata.php | 45 +++++++++++++++- 10 files changed, 130 insertions(+), 32 deletions(-) diff --git a/UPGRADE-7.4.md b/UPGRADE-7.4.md index 459a43dd247cb..1593073d06aaf 100644 --- a/UPGRADE-7.4.md +++ b/UPGRADE-7.4.md @@ -84,6 +84,7 @@ Translation Validator --------- + * Deprecate implementing `__sleep/wakeup()` on `GenericMetadata` implementations; use `__(un)serialize()` instead * Deprecate passing a list of choices to the first argument of the `Choice` constraint. Use the `choices` option instead * Deprecate `getRequiredOptions()` and `getDefaultOption()` methods of the `All`, `AtLeastOneOf`, `CardScheme`, `Collection`, `CssColor`, `Expression`, `Regex`, `Sequentially`, `Type`, and `When` constraints diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index 0f863452eff10..41374405c38ba 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -136,9 +136,7 @@ public function __unserialize(array $data): void } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0 */ public function __sleep(): array { @@ -148,9 +146,7 @@ public function __sleep(): array } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__unserialize()` in 8.0 */ public function __wakeup(): void { diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index d193637c7615a..8ac5b6c7e043e 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -846,9 +846,7 @@ public function __unserialize(array $data): void } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0 */ public function __sleep(): array { @@ -858,9 +856,7 @@ public function __sleep(): array } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__unserialize()` in 8.0 */ public function __wakeup(): void { diff --git a/src/Symfony/Component/String/AbstractString.php b/src/Symfony/Component/String/AbstractString.php index 69f6ba5e1950c..4777f95117b1b 100644 --- a/src/Symfony/Component/String/AbstractString.php +++ b/src/Symfony/Component/String/AbstractString.php @@ -729,9 +729,7 @@ public function __serialize(): array } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__unserialize()` in 8.0 */ public function __sleep(): array { diff --git a/src/Symfony/Component/String/LazyString.php b/src/Symfony/Component/String/LazyString.php index d250c288fc55e..eafc9ca9e7522 100644 --- a/src/Symfony/Component/String/LazyString.php +++ b/src/Symfony/Component/String/LazyString.php @@ -126,12 +126,12 @@ public function __serialize(): array } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0 */ public function __sleep(): array { + trigger_deprecation('symfony/string', '7.4', 'Calling "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + $this->__toString(); return ['value']; diff --git a/src/Symfony/Component/String/UnicodeString.php b/src/Symfony/Component/String/UnicodeString.php index 4da506aeb0847..f2bf1d0a997f7 100644 --- a/src/Symfony/Component/String/UnicodeString.php +++ b/src/Symfony/Component/String/UnicodeString.php @@ -406,9 +406,7 @@ public function __unserialize(array $data): void } /** - * @internal since Symfony 7.4, will be removed in 8.0 - * - * @final since Symfony 7.4, will be removed in 8.0 + * @deprecated since Symfony 7.4, will be replaced by `__unserialize()` in 8.0 */ public function __wakeup(): void { diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index c95fc1b84ade7..9bc83027b79b8 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.4 --- + * Deprecate implementing `__sleep/wakeup()` on `GenericMetadata` implementations; use `__(un)serialize()` instead * Deprecate passing a list of choices to the first argument of the `Choice` constraint. Use the `choices` option instead * Add the `min` and `max` parameter to the `Length` constraint violation * Deprecate `getRequiredOptions()` and `getDefaultOption()` methods of the `All`, `AtLeastOneOf`, `CardScheme`, `Collection`, diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index d812255c43b27..582f75c5b9b9d 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -119,14 +119,53 @@ public function __construct(string $class) } } - public function __sleep(): array + public function __serialize(): array { - $parentProperties = parent::__sleep(); + if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) { + return [ + 'constraints' => $this->constraints, + 'constraintsByGroup' => $this->constraintsByGroup, + 'traversalStrategy' => $this->traversalStrategy, + 'autoMappingStrategy' => $this->autoMappingStrategy, + 'getters' => $this->getters, + 'groupSequence' => $this->groupSequence, + 'groupSequenceProvider' => $this->groupSequenceProvider, + 'groupProvider' => $this->groupProvider, + 'members' => $this->members, + 'name' => $this->name, + 'properties' => $this->properties, + 'defaultGroup' => $this->defaultGroup, + ]; + } + + trigger_deprecation('symfony/validator', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + + $data = []; + foreach ($this->__sleep() as $key) { + try { + if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) { + $data[$key] = $r->getValue($this); + } + } catch (\ReflectionException) { + $data[$key] = $this->$key; + } + } - // Don't store the cascading strategy. Classes never cascade. - unset($parentProperties[array_search('cascadingStrategy', $parentProperties)]); + return $data; + } + + /** + * @deprecated since Symfony 7.4, will be removed in 8.0 + */ + public function __sleep(): array + { + trigger_deprecation('symfony/validator', '7.4', 'Calling "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); - return array_merge($parentProperties, [ + return [ + 'constraints', + 'constraintsByGroup', + 'traversalStrategy', + 'autoMappingStrategy', 'getters', 'groupSequence', 'groupSequenceProvider', @@ -135,7 +174,7 @@ public function __sleep(): array 'name', 'properties', 'defaultGroup', - ]); + ]; } public function getClassName(): string diff --git a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php index 43992255c9e56..b5f0005dd68b0 100644 --- a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php @@ -83,13 +83,41 @@ class GenericMetadata implements MetadataInterface */ public int $autoMappingStrategy = AutoMappingStrategy::NONE; + public function __serialize(): array + { + if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) { + return [ + 'constraints' => $this->constraints, + 'constraintsByGroup' => $this->constraintsByGroup, + 'cascadingStrategy' => $this->cascadingStrategy, + 'traversalStrategy' => $this->traversalStrategy, + 'autoMappingStrategy' => $this->autoMappingStrategy, + ]; + } + + trigger_deprecation('symfony/validator', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + + $data = []; + foreach ($this->__sleep() as $key) { + try { + if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) { + $data[$key] = $r->getValue($this); + } + } catch (\ReflectionException) { + $data[$key] = $this->$key; + } + } + + return $data; + } + /** - * Returns the names of the properties that should be serialized. - * - * @return string[] + * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0 */ public function __sleep(): array { + trigger_deprecation('symfony/validator', '7.4', 'Calling "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + return [ 'constraints', 'constraintsByGroup', diff --git a/src/Symfony/Component/Validator/Mapping/MemberMetadata.php b/src/Symfony/Component/Validator/Mapping/MemberMetadata.php index 6df8add12c564..076548ec4a9fd 100644 --- a/src/Symfony/Component/Validator/Mapping/MemberMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/MemberMetadata.php @@ -76,13 +76,54 @@ public function addConstraint(Constraint $constraint): static return $this; } + public function __serialize(): array + { + if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) { + return [ + 'constraints' => $this->constraints, + 'constraintsByGroup' => $this->constraintsByGroup, + 'cascadingStrategy' => $this->cascadingStrategy, + 'traversalStrategy' => $this->traversalStrategy, + 'autoMappingStrategy' => $this->autoMappingStrategy, + 'class' => $this->class, + 'name' => $this->name, + 'property' => $this->property, + ]; + } + + trigger_deprecation('symfony/validator', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + + $data = []; + foreach ($this->__sleep() as $key) { + try { + if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) { + $data[$key] = $r->getValue($this); + } + } catch (\ReflectionException) { + $data[$key] = $this->$key; + } + } + + return $data; + } + + /** + * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0 + */ public function __sleep(): array { - return array_merge(parent::__sleep(), [ + trigger_deprecation('symfony/validator', '7.4', 'Calling "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this)); + + return [ + 'constraints', + 'constraintsByGroup', + 'cascadingStrategy', + 'traversalStrategy', + 'autoMappingStrategy', 'class', 'name', 'property', - ]); + ]; } /**