Problem/Motivation
PHP has passed an RFC to soft deprecate the use of __sleep() and __wakeup() in favor of __serialize() and __unserialize(): https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup
This is after initially an RFC to deprecate them in PHP 8.5 had passed, but was reconsidered because the full scope was underestimated:
Symfony has already addressed it.
But core has wider usage overriding seriazed keys, especially in container serialization and missed transition to use the Serialzable interface.
New approach (since PHP 7.4) is using https://wiki.php.net/rfc/custom_object_serialization and since PHP 8.1 using the Serializable interface is deprecated without magic methods
In addition, __wakeup() does not support setting readonly parameters, see examples:
https://3v4l.org/OPTLj
https://3v4l.org/3mViB
(Note that judging from core CI runs, this might have been fixed in PHP 8.5.6: See https://git.drupalcode.org/project/drupal/-/jobs/9745198 on 8.5.6 (successful Drupal\Tests\node\Functional\NodeAccessRebuildNodeGrantsTest) vs this browser output artifact Drupal\Tests\node\Functional\NodeAccessRebuildNodeGrantsTest on PHP 8.3 (11.x)
Setting readonly properties is supported in __unserialize()
https://3v4l.org/G0WCa
Steps to reproduce
(Outdated since deprecation reverted)
See core's unit tests using PHP 8.5 in latest pipelines
Deprecated: The __wakeup() serialization magic method has been deprecated. Implement __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /builds/issue/drupal-3548957/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php on line 12
Deprecated: The __sleep() serialization magic method has been deprecated. Implement __serialize() instead (or in addition, if support for old PHP versions is necessary) in /builds/issue/drupal-3548957/core/lib/Drupal/Core/Database/Connection.php on line 29
Deprecated: The __sleep() serialization magic method has been deprecated. Implement __serialize() instead (or in addition, if support for old PHP versions is necessary) in /builds/issue/drupal-3548957/core/lib/Drupal/Core/Cache/MemoryBackend.php on line 23Proposed resolution
- replace methods as suggested
- provide BC
- write CR
Remaining tasks
MR: https://git.drupalcode.org/project/drupal/-/merge_requests/15448
This provides BC for subclasses that implementing __sleep and __wakeup
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3548971
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
andypostadded about https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup
Also Laravel working on it https://github.com/laravel/framework/pull/57032
Comment #3
andypostComment #4
godotislateMagic methods don't seem to be addressed specifically in the BC policy, but they seem to fall under "Underscore-prefixed functions and methods" and "Public methods not specified in an interface" as internal code.
That being said, it seems reasonable there may be contrib or custom classes that use DependencySerializationTrait and rely on overriding the trait's
__sleep()and__wakeup()so that they can be safely cached or otherwise stored to the database.Maybe in DependencySerializationTrait,
__serialize()and__unserialize()can be implemented to call__sleep()and__wakeup(), so that any subclass implementing the latter methods will still have those invoked. It might also be possible to add a boolean flag property in the trait, and that flag is set to TRUE when__sleep()and__wakeup()are called by__serialize()and__unserialize(), and then otherwise a deprecation triggered.So roughly something like this:
Any class that overrides __sleep() or __wakeup() would need to call the trait's method in order to trigger deprecation, though.
This could also apply to similar situations other than use of DependencySerializationTrait.
Comment #5
andypostPHP reverted deprecation for 8.5 so making this optional but as clean-up it still makes sense and for futureproof
Ref https://github.com/php/php-src/commit/fc353966f3976f733a2d038ce9b29016c4...
Comment #7
andypostI still think it should change serialization at least for none-trait places
Comment #9
andypostI bet it needs split on issues so I started to backport changes https://git.drupalcode.org/project/drupal/-/merge_requests/12877/diffs?c...
Also it may need a sniffer or phpstan rule to catch remains
Comment #10
godotislateComing from #3424344: Allow DependencySerializationTrait to work with readonly properties: readonly properties can't be set in __wakeup(), but they can in __unserialize(), which might be a good reason to include DependencySerializationTrait in scope here. Or if not, to create an issue for to deprecate __sleep()/__wakeup() in the trait and use __serialize()/__unserialize().
Comment #11
godotislateComment #12
andypostThanks, the issue was supposed to be a plan/meta as every case here needs own issue it was delayed as 8.5 serialization been relaxed but now 8.6 is coming)
So let's fix the trait first and then decide about split
Comment #14
godotislateI copied over a lot of MR 15051 to MR 15448, then did a separate approach for DependencySerializationTrait, because one problem to address is this:
__sleep()and__wakeup()to add its own special handling__serialize()and__unserialize(),__sleep()and__wakeup()don't runThe MR tries check whether the class itself implements __sleep or __wakeup, and to run them from __serialize or __unserialize. A bunch of tests are failing though. Will need more investigation.
Other concern:
Can objects that have been serialized and stored in the DB before the switch to __serialize and __unserialize still be able to be unserialized?
Comment #15
godotislateTook another shot at this. I restarted https://git.drupalcode.org/project/drupal/-/merge_requests/15448 from scratch to address test failures one by one. After it's green, I'll compare with https://git.drupalcode.org/project/drupal/-/merge_requests/15051 to see if it's missing anything, but I'm still working through test failures.
This is no on one of the tests at least, but I may be able to rewrite the relevant unserialize/serialize method to more closely resemble what sleep/wakeup did before.
Comment #16
godotislateOK, finally got https://git.drupalcode.org/project/drupal/-/merge_requests/15448 green.
Still need to review https://git.drupalcode.org/project/drupal/-/merge_requests/15051 to see if MR 15448 is missing anything from it, though the normalization method was very usefuly to pass tests.
Along with that, probably need to clean up a few things.
The general approach is this:
Introduced two new traits that provide __serialize and __sleep, as well as __unserialize and __wakeup.
For classes that use the traits, on serialization, __serialize will check if there's an implementation of __sleep in the class that overrides the implementation of __sleep in the trait. If so, it will call __sleep.
Both __serialize and __sleep in the trait call an abstract function doSerialize(), which should be implemented in the class, and basically performs everything that typicall would be done in __serialize. This way __serialize and __sleep should work the same (with __sleep just returing the array keys), and this is to provide BC in case either the subclass's __sleep method calls the parent, or if some external code calls __sleep.
There is similar functionality for __unserialize and __wakeup with an abstract doUnserialize method.
Still outstanding is adding test coverage to show that the BC layer actually works.
Comment #17
andypostnice idea with traits! looks this way it can give real BC
Comment #18
godotislateOK, MR https://git.drupalcode.org/project/drupal/-/merge_requests/15448 is ready.
I added a test class from https://git.drupalcode.org/project/drupal/-/merge_requests/15051 and cleaned some things up.
I also added tests for the BC layer.
I reviewed the CR and it seems fine. I made small edit to add that
__wakeupcan not set readonly properties, while__unserializecan.I'm hiding https://git.drupalcode.org/project/drupal/-/merge_requests/15051. Hope that's OK, let me know if there are any issues.
Comment #20
godotislateInterestingly, the PHP RFC to "soft" deprecate __sleep and __wakeup talks about the same challenges we've had to address here with BC.
Comment #21
godotislateUpdated the IS for latest status.
Comment #22
godotislate