Skip to content

Replace __sleep/__wakeup with __serialize/__unserialize#2962

Merged
GromNaN merged 1 commit intodoctrine:3.0.xfrom
GromNaN:3-serialize
Dec 19, 2025
Merged

Replace __sleep/__wakeup with __serialize/__unserialize#2962
GromNaN merged 1 commit intodoctrine:3.0.xfrom
GromNaN:3-serialize

Conversation

@GromNaN
Copy link
Member

@GromNaN GromNaN commented Dec 7, 2025

Q A
Type improvement
BC Break yes
Fixed issues -

Summary

The magic methods __sleep and __wakeup are being soft-deprecated (RFC). Replaced by __serialize and __unserialize. This new methods are more verbose.

Similar to symfony/symfony#61727

@GromNaN GromNaN added this to the 3.0.0 milestone Dec 7, 2025
@GromNaN GromNaN requested a review from Copilot December 7, 2025 00:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the codebase by replacing the soft-deprecated __sleep and __wakeup magic methods with their more verbose counterparts __serialize and __unserialize, following PHP's RFC for soft-deprecation.

Key Changes:

  • Migration from __sleep/__wakeup to __serialize/__unserialize in serialization logic
  • Enhanced serialization methods that return associative arrays with explicit key-value pairs instead of property name arrays
  • Updated return type annotations to reflect the new structure (array<string, mixed> instead of string[])

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/PersistentCollection/PersistentCollectionTrait.php Converted __sleep to __serialize, now returning explicit key-value pairs for collection state
src/Mapping/ClassMetadata.php Replaced __sleep/__wakeup with __serialize/__unserialize, restructuring conditional serialization logic to use associative array assignments

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep(): array
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This methods should be marked as @internal or @deprecated in 2.x? They should never be called directly or overridden.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClassMetadata is already marked as @final but we should also mark these methods as @deprecated to avoid direct calling them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, I'd argue that the magic methods are not meant to be called directly, and thus shouldn't need @internal or @deprecated. Instead, these methods define behaviour of the class which in this case doesn't change -- we're just changing the points where we hook in.
As for a potential compatibility layer in v2, we may want to rely on deprecation notices in certain places to highlight upcoming changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a BC layer in #2965

continue;
}

if (method_exists($mapping['collectionClass'], '__sleep')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this should be in the generator class, as this command is typically not called in development environments. We also need to consider a compatibility layer in v2 to allow people to be notified of the upcoming change in v3 and implement __serialize instead.

Copy link
Member Author

@GromNaN GromNaN Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that this trait is added on generated classes that extends user defined classes. The __sleep method is alreadyoverridden by the trait one. So, not functioning. I'll remove this error.

];

// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy !== self::CHANGETRACKING_DEFERRED_IMPLICIT) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it's worth keeping the conditionals around. Keeping a map of fields to serialise would also make the unserialisation more secure (see comment below).

foreach ($data as $field => $value) {
$this->$field = $value;
foreach ($data as $property => $value) {
$this->$property = $value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how big an issue this still is, but this would technically allow people to override properties that we don't actually serialise or intend to read from serialised data. Paired with the comment above, having a map of all properties we want to serialise would allow us to re-use this map and only use data from fields that we know should be serialised.

Copy link
Member Author

@GromNaN GromNaN Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unserialization is in the hotpath. I think it's an optimization to only serialize the data that is different from the default value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for overriding private properties that are not part of the metadata, that's a stretch. We can also use reflection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good -- since we're not making it any worse I'm fine leaving this as-is.

@GromNaN GromNaN merged commit 61de6b2 into doctrine:3.0.x Dec 19, 2025
15 checks passed
@GromNaN GromNaN deleted the 3-serialize branch December 19, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants