# [RFC] Soft-Deprecate __sleep() and __wakeup()

- Thread: https://externals.io/message/128643
- Original archive: https://news-web.php.net/php.internals/128643
- Started by Nicolas Grekas on 2025-09-05T15:53:20+00:00
- Messages: 20
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #128643 — Nicolas Grekas — 2025-09-05T15:53:20+00:00

URL: https://externals.io/message/128643#128643

Hello internals,

Following the discussion that started at
https://externals.io/message/128226#128456 I wrote this RFC to formalize
our consensus on the topic.

TL;DR, this is about converting the deprecation of __sleep and __wakeup to
a documentation-based soft deprecation:
https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup

Cheers,
Nicolas

---

## #128655 — tim@bastelstu.be — 2025-09-08T14:45:59+00:00

URL: https://externals.io/message/128643#128655 · In reply to: #128643

Hi

Am 2025-09-05 17:53, schrieb Nicolas Grekas:
> Hello internals,
> 
> Following the discussion that started at
> https://externals.io/message/128226#128456 I wrote this RFC to 
> formalize
> our consensus on the topic.
> 
> TL;DR, this is about converting the deprecation of __sleep and __wakeup 
> to
> a documentation-based soft deprecation:
> https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup

Thank you for the RFC. I have some comments:

1.

I disagree with the phrasing that the RFC passed with a “narrow margin”. 
While it is technically true, that this is the narrowest margin for 
accepting an RFC, the necessary margins are already biased in favor of 
not accepting an RFC. That the RFC was accepted means that a significant 
majority of voters were in favor of the deprecation. I did not vote, 
since I did not have sufficient time to form an opinion on the RFC, but 
given the knowledge I've gained as part of the discussion I would now 
vote in favor of the RFC.

2.

The examples are biased. As an example, the initial “User” example has a 
serialization hook that is completely useless. The other examples try to 
replicate `__sleep()`'s broken behavior exactly, which seems to be a 
relevant requirement in the real world for only a minority of users.

3.

Similarly, I believe that the RFC *overstates* the cost of the 
deprecation. From my experience a majority of serialization hooks will 
just unconditionally throw an exception to prevent serialization. The 
truth is probably somewhere in the middle.

4.

The RFC correctly acknowleges that `__sleep()` is broken with regard to 
private properties, but at the same time claims that the deprecation 
does not fix a “correctness problem”, which is a contradiction.

5.

The serialization mechanism is also a security sensitive part of the 
language, the fewer moving parts there are, the better. Security is part 
of the motivation for me.

----------------------

That all said, as I've said before: I see that replacing __wakeup() by 
__unserialize() is non-trivial and I would be okay with deferring that 
one until we have some helper (e.g. `**s**et_mangled_object_vars`). But 
__sleep() can just go away.

Best regards
Tim Düsterhus

---

## #128657 — Jakub Zelenka — 2025-09-08T15:32:13+00:00

URL: https://externals.io/message/128643#128657 · In reply to: #128655

Hi,



> Hi
>
> Am 2025-09-05 17:53, schrieb Nicolas Grekas:
> > […]
>
> Thank you for the RFC. I have some comments:
>
> 1.
>
> I disagree with the phrasing that the RFC passed with a “narrow margin”.
> While it is technically true, that this is the narrowest margin for
> accepting an RFC, the necessary margins are already biased in favor of
> not accepting an RFC. That the RFC was accepted means that a significant
> majority of voters were in favor of the deprecation. I did not vote,
> since I did not have sufficient time to form an opinion on the RFC, but
> given the knowledge I've gained as part of the discussion I would now
> vote in favor of the RFC.
>
>
I think the point here was that it was close and the RFC itself was
misleading and omitted some important points that would like change the
final result.


> 5.
>
> The serialization mechanism is also a security sensitive part of the
> language, the fewer moving parts there are, the better. Security is part
> of the motivation for me.
>
>
Could you be more specific here? We do not consider issues (crashes and
similar) resulting from unserializing of the serialized string as security
issues because it must not come from the untrusted source (see
https://www.php.net/manual/en/function.unserialize.php ). I don't remember
any security issue in serialize / unserialize since this rule was set.

Kind Regards

Jakub

---

## #128659 — Daniel Scherzer — 2025-09-08T17:25:09+00:00

URL: https://externals.io/message/128643#128659 · In reply to: #128643

On Mon, Sep 8, 2025 at 8:21 PM Nicolas Grekas <nicolas.grekas+php@gmail.com>
wrote:

> Hello internals,
>
> Following the discussion that started at
> https://externals.io/message/128226#128456 I wrote this RFC to formalize
> our consensus on the topic.
>
> TL;DR, this is about converting the deprecation of __sleep and __wakeup to
> a documentation-based soft deprecation:
> https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup
>
> Cheers,
> Nicolas
>

The PHP 8.5 RM team has discussed this internally, and arrived at the
following. A full explanation of our reasoning follows.

- Given the accepted RFC for deprecating `__sleep()` and `__wakeup()` in
PHP 8.5, we should aim to merge the deprecation in time for PHP 8.5, i.e.
before PHP-8.5 is branched on September 23.
- If the RFC to switch the deprecation to a "soft deprecation" is accepted,
the RM team is comfortable with landing a revert of the deprecation as long
as the revert can land before RC2.

Our reasoning is as follows ("hard deprecation" means the warnings, "soft
deprecation" is just the documentation):

1. We cannot assume that the soft deprecation RFC will be accepted.
However, if we wait until we know for certain that the RFC fails, it would
be too late to *then* merge the hard deprecation. By our math, if the soft
deprecation RFC had exactly 2 weeks of discussion and then 2 weeks of
voting, the earliest it would close is October 4, with RC*2* being tagged
October 7.

2. Since we cannot merge the hard deprecation after RC1, the hard
deprecation either needs to go into PHP 8.5 before RC1, or be delayed until
the next release. Since there was an RFC for doing the deprecation in PHP
8.5 that got accepted, 8.5 should be preferred.

3. Having a hard deprecation in PHP 8.5, and converting it to a soft
deprecation in PHP 8.6 (or PHP 9.0, whatever is next), does not make sense.
For the soft deprecation RFC to be meaningful, we would need to not have
the hard deprecation warnings in PHP 8.5.

4. If the hard deprecation is implemented for 8.5 (per note 2) but the soft
deprecation RFC is accepted, then (per note 3) we should remove the hard
deprecation warnings from PHP 8.5. However, such a relatively large change
should not be made too close to the GA release of PHP 8.5.0. Release
candidates are meant to match the eventual release as closely as possible.

5. Given the minimum schedule outlined in note 1 above, there are a few
days before the soft deprecation RFC could finish voting and when RC2 is
packaged. This should be enough time to land a revert of the hard
deprecation, given that a) the patch can be reviewed and approved before
the RFC finishes, and b) the patch is likely to be just a revert of the
original deprecation patches. By removing the warnings from RC2, community
developers waiting to test the release candidates until after the warnings
were removed can have 3 release candidates to do so.

Thanks,
--Daniel Scherzer, Volker Dusch, and Pierrick Charron

---

## #128660 — tim@bastelstu.be — 2025-09-08T20:44:33+00:00

URL: https://externals.io/message/128643#128660 · In reply to: #128657

Hi


> I think the point here was that it was close and the RFC itself was

Again, a 2/3 majority is *not* close. Twice the number of folks were in 
favor than against the RFC.

> misleading and omitted some important points that would like change the
> final result.

I concede that “straight up improvement” might not be perfectly accurate 
for `__wakeup()`, but for `__sleep()` it *is* accurate. `__sleep()` is 
broken and there's a straight-forward migration to `__serialize()`.

I appreciate that both of you communicated your concerns with the 
proposed deprecation during the discussion, but you basically just said 
“I believe the impact is too large”, which is not actionable feedback 
for the RFC author and also doesn't help voters make an educated 
decision. The point of the discussion phase is figuring out these 
details together.

> > […]
> Could you be more specific here? We do not consider issues (crashes and
> similar) resulting from unserializing of the serialized string as security
> issues because it must not come from the untrusted source (see
> https://www.php.net/manual/en/function.unserialize.php ). I don't remember
> any security issue in serialize / unserialize since this rule was set.

Even when only dealing with trusted data, unserialize needs to parse 
inputs (which is already sufficiently dangerous in C) and it also needs 
to deal with partial(ly initialized) object graphs all while executing 
arbitrary (userland) code that may or may not interact in weird ways 
(e.g. when error handlers get involved due to a bug in a custom 
unserialize hook). And of course there can also be bugs with the 
serializer that result in “trusted” output that triggers unexpected and 
untested code-paths, particularly when references or cycles get 
involved. When running with mixed PHP versions during an incremental 
upgrade it might also be possible for serialization data to be emitted 
by newer PHP versions that may not be anticipated by older PHP versions 
and that trigger unexpected code-paths.

And then there's also stuff like 
https://wiki.php.net/rfc/unserialize_warn_on_trailing_data, which can 
happen due to bugs in a userland implementation even when not doing 
unserialize($_GET['stuff']).

Saying that “unserialize is not security-relevant because you must only 
feed it safe inputs” as an excuse to avoid making unserialize safer is 
not helping anyone and is downplaying the risks involved in unserialization.

For all those reasons, I've intentionally tried to make the 
unserialization hooks as robust as possible during review of newly added 
classes (e.g. ext/random, ext/uri, and also 
https://github.com/php/php-src/pull/19447), making them carefully check 
the structure of the serialization input and also having tests that 
verify robustness even when facing untrusted inputs, because that's just 
something that will happen in the real world, despite the documentation 
advising against it.

Best regards
Tim Düsterhus

---

## #128661 — Jakub Zelenka — 2025-09-08T21:14:24+00:00

URL: https://externals.io/message/128643#128661 · In reply to: #128660

Hi,



> Hi
>
> 
> > […]
>
> Again, a 2/3 majority is *not* close. Twice the number of folks were in
> favor than against the RFC.
>
>
I meant close to the actual threshold (not close vote). Again if single
person changed their mind because of the facts below (which is quite
likely), it might not have passed.

This RFC is just about to see if people can see that there is significantly
more effort needed for this migration. It just tries to make sure that
people can vote on the right description. If they don't think, that's wort
it to change the result, then so be it. But I think it's fair to provide an
RFC with a correct description so it can be properly decided.


> > […]
>
> I concede that “straight up improvement” might not be perfectly accurate
> for `__wakeup()`, but for `__sleep()` it *is* accurate. `__sleep()` is
> broken and there's a straight-forward migration to `__serialize()`.
>
> I appreciate that both of you communicated your concerns with the
> proposed deprecation during the discussion, but you basically just said
> “I believe the impact is too large”, which is not actionable feedback
> for the RFC author and also doesn't help voters make an educated
> decision. The point of the discussion phase is figuring out these
> details together.
>
>
Yeah as I mentioned it was also my fault not to point this out sooner but
it's hard to verify every single thing in detail if there are like 50
deprecations proposed.


> > […]
> security
> > […]
> remember
> > […]
>
> Even when only dealing with trusted data, unserialize needs to parse
> inputs (which is already sufficiently dangerous in C) and it also needs
> to deal with partial(ly initialized) object graphs all while executing
> arbitrary (userland) code that may or may not interact in weird ways
> (e.g. when error handlers get involved due to a bug in a custom
> unserialize hook). And of course there can also be bugs with the
> serializer that result in “trusted” output that triggers unexpected and
> untested code-paths, particularly when references or cycles get
> involved. When running with mixed PHP versions during an incremental
> upgrade it might also be possible for serialization data to be emitted
> by newer PHP versions that may not be anticipated by older PHP versions
> and that trigger unexpected code-paths.
>
>
I understand your concern about the complexity but this can apply to many
other parts in php-src. As I'm sure you know, this still wouldn't likely to
be considered as a security issue.


> And then there's also stuff like
> https://wiki.php.net/rfc/unserialize_warn_on_trailing_data, which can
> happen due to bugs in a userland implementation even when not doing
> unserialize($_GET['stuff']).
>
>
This could be closer but we wouldn't like find exploit either. At least
this wasn't even raised as a security issue so I guess you were expecting
that not to be a security problem.


> Saying that “unserialize is not security-relevant because you must only
> feed it safe inputs” as an excuse to avoid making unserialize safer is
> not helping anyone and is downplaying the risks involved in
> unserialization.
>
>
I don't have problem with making unserialize safer as there might be users
that use it improperly.  But we shouldn't be saying that this is a security
sensitive part when we don't consider those sort of issues as security
issues because none of those issues will get fixed in our security support
only releases. In that sense I don't think we can consider it as a security
sensitive part.

Kind regards

Jakub

---

## #128663 — tim@bastelstu.be — 2025-09-09T13:39:51+00:00

URL: https://externals.io/message/128643#128663 · In reply to: #128661

Hi

Am 2025-09-08 23:14, schrieb Jakub Zelenka:
> I understand your concern about the complexity but this can apply to 
> many
> other parts in php-src. As I'm sure you know, this still wouldn't 
> likely to
> be considered as a security issue.

I've intentionally said “security sensitive”. I believe the risk of 
security issues for the unserializer is significantly higher than in 
other parts of the language and I also believe that by keeping 
complexity down it is both easier to verify correctness and also to fix 
any bugs that crop up. From what I see __wakeup() and __unserialize() 
work quite differently internally. When there's __unserialize(), the 
deserialization process only creates an empty object shell (similarly to 
newInstanceWithoutConstructor) and then calls __unserialize() at the 
very end. For __wakeup() all the properties are filled directly and then 
__wakeup() is called at the end. In both cases the destructor is skipped 
for all following objects once one of the deserialization hooks fails.

For __wakeup() this has the interesting effect that in case of circular 
structures, some objects may appear to already be properly initialized 
(all the properties are there), but __wakeup() has not executed yet, 
potentially making them unsafe to touch. In case of __unserialize() the 
objects are clearly in a partially initialized state (e.g. properties 
being uninit), which I'd claim is safer:

     <?php

     class A {
         public $a;

         public function __construct(public string $name)
         {

         }

         public function __unserialize(array $data): void
         {
             $this->a = $data['a'];
             $this->name = $data['name'];
             echo "Waking up ", $this->name, PHP_EOL;
             var_dump($this->a->name);
         }

         public function __wakeup(): void
         {
             echo "Waking up ", $this->name, PHP_EOL;
             var_dump($this->a->name);
         }

         public function __destruct()
         {
             echo __METHOD__, PHP_EOL;
         }
     }

     $a = new A('A');
     $a->a = new A('B');
     $a->a->a = new A('C');
     $a->a->a->a = $a;

     echo "Before", PHP_EOL;
     var_dump(unserialize(serialize($a)));
     echo "After", PHP_EOL;

In case of `__unserialize()` the unsafe access to `$this->a->name` will 
throw, whereas in `__wakeup()` it will return `A`, despite `A` not being 
fully available yet. Similarly skipping the destructor for an empty 
object shell is safer than skipping the destructor for an object that 
may appear usable.

> > […]
> I don't have problem with making unserialize safer as there might be 
> users
> that use it improperly.  But we shouldn't be saying that this is a 
> security
> sensitive part when we don't consider those sort of issues as security
> issues because none of those issues will get fixed in our security 
> support
> only releases. In that sense I don't think we can consider it as a 
> security
> sensitive part.

The unserializer already contains quite a bit of logic to make it as 
safe as possible, e.g. running the unserialization hooks only at the 
very end and skipping destructors for objects where the unserialization 
hook didn't successfully run. The forefathers definitely considered 
possible edge cases that might lead to security issues.

Best regards
Tim Düsterhus

---

## #128664 — Jakub Zelenka — 2025-09-10T09:26:29+00:00

URL: https://externals.io/message/128643#128664 · In reply to: #128663

Hi,



> Hi
>
> Am 2025-09-08 23:14, schrieb Jakub Zelenka:
> > […]
>
> I've intentionally said “security sensitive”. I believe the risk of
> security issues for the unserializer is significantly higher than in
> other parts of the language and I also believe that by keeping
> complexity down it is both easier to verify correctness and also to fix
> any bugs that crop up. From what I see __wakeup() and __unserialize()
> work quite differently internally. When there's __unserialize(), the
> deserialization process only creates an empty object shell (similarly to
> newInstanceWithoutConstructor) and then calls __unserialize() at the
> very end. For __wakeup() all the properties are filled directly and then
> __wakeup() is called at the end. In both cases the destructor is skipped
> for all following objects once one of the deserialization hooks fails.
>
> For __wakeup() this has the interesting effect that in case of circular
> structures, some objects may appear to already be properly initialized
> (all the properties are there), but __wakeup() has not executed yet,
> potentially making them unsafe to touch. In case of __unserialize() the
> objects are clearly in a partially initialized state (e.g. properties
> being uninit), which I'd claim is safer:
>
>      <?php
>
>      class A {
>          public $a;
>
>          public function __construct(public string $name)
>          {
>
>          }
>
>          public function __unserialize(array $data): void
>          {
>              $this->a = $data['a'];
>              $this->name = $data['name'];
>              echo "Waking up ", $this->name, PHP_EOL;
>              var_dump($this->a->name);
>          }
>
>          public function __wakeup(): void
>          {
>              echo "Waking up ", $this->name, PHP_EOL;
>              var_dump($this->a->name);
>          }
>
>          public function __destruct()
>          {
>              echo __METHOD__, PHP_EOL;
>          }
>      }
>
>      $a = new A('A');
>      $a->a = new A('B');
>      $a->a->a = new A('C');
>      $a->a->a->a = $a;
>
>      echo "Before", PHP_EOL;
>      var_dump(unserialize(serialize($a)));
>      echo "After", PHP_EOL;
>
> In case of `__unserialize()` the unsafe access to `$this->a->name` will
> throw, whereas in `__wakeup()` it will return `A`, despite `A` not being
> fully available yet. Similarly skipping the destructor for an empty
> object shell is safer than skipping the destructor for an object that
> may appear usable.
>
> > […]
>
> The unserializer already contains quite a bit of logic to make it as
> safe as possible, e.g. running the unserialization hooks only at the
> very end and skipping destructors for objects where the unserialization
> hook didn't successfully run. The forefathers definitely considered
> possible edge cases that might lead to security issues.
>
>
I can see what you mean but you could say in the same way that many parts
in the engine and other parts are security sensitive. Almost anything that
is complex can lead to a security issue given some preconditions. The fact
is that we have not had any serialization issue for a long time so to me
there are places that are more security sensitive and more problematic than
seriallization.

Kind regards,

Jakub

---

## #128665 — Jakub Zelenka — 2025-09-10T13:23:15+00:00

URL: https://externals.io/message/128643#128665 · In reply to: #128643

Hi,

On Fri, Sep 5, 2025 at 5:55 PM Nicolas Grekas <nicolas.grekas+php@gmail.com>
wrote:

> Hello internals,
>
> Following the discussion that started at
> https://externals.io/message/128226#128456 I wrote this RFC to formalize
> our consensus on the topic.
>
> TL;DR, this is about converting the deprecation of __sleep and __wakeup to
> a documentation-based soft deprecation:
> https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup
>
>
We just had a discussion privately about this and I came with one example
that would be worth to add here. It is about storing the serialized string
where application needs to care about working correctly with the old
format. For example when object is serialized, that string is stored into
database. So when the application is deployed, it should still work in the
same way when unserializing the string.

If __sleep is used to serialize private properties (not all but just some),
then those property names are stored in the mangled format ("\x00" .
self::class . "\x00" prefix). It means to make it compatible in
__serialize, the application has to mangle property names - this can be
done either manually prefixing the name or using get_mangled_object_vars
and filter the mangled names. Alternatively it could use __serialize with
the new names but then it will need to deal with new and old (mangled)
formats in __unserialize. In any case it means that the users will be
required to deal with the mangled property name and get some understanding
of mangling.

Kind regards,

Jakub

---

## #128666 — Jakub Zelenka — 2025-09-10T14:09:41+00:00

URL: https://externals.io/message/128643#128666 · In reply to: #128665

Hi,



> Hi,
>
> On Fri, Sep 5, 2025 at 5:55 PM Nicolas Grekas <
> nicolas.grekas+php@gmail.com> wrote:
>
> > […]
> We just had a discussion privately about this and I came with one example
> that would be worth to add here. It is about storing the serialized string
> where application needs to care about working correctly with the old
> format. For example when object is serialized, that string is stored into
> database. So when the application is deployed, it should still work in the
> same way when unserializing the string.
>
> If __sleep is used to serialize private properties (not all but just
> some), then those property names are stored in the mangled format ("\x00" .
> self::class . "\x00" prefix). It means to make it compatible in
> __serialize, the application has to mangle property names - this can be
> done either manually prefixing the name or using get_mangled_object_vars
> and filter the mangled names. Alternatively it could use __serialize with
> the new names but then it will need to deal with new and old (mangled)
> formats in __unserialize. In any case it means that the users will be
> required to deal with the mangled property name and get some understanding
> of mangling.
>

I just had a chat with Nicolas and he asked me to add it and co-author the
RFC so the section added here:
https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup#complex_handling_of_mangled_property_names_with_persistent_storage

Kind regards,

Jakub

---

## #128667 — Jakub Zelenka — 2025-09-10T15:39:38+00:00

URL: https://externals.io/message/128643#128667 · In reply to: #128655

Hi,



> I disagree with the phrasing that the RFC passed with a “narrow margin”.
>

I just updated the wording so it now says:

> A recent RFC to deprecate the __sleep() and __wakeup() magic methods in
favor of __serialize() and __unserialize() passed (18–9), but only just met
the required 2/3 majority.

Hope it's better! :)

Kind regards,

Jakub

---

## #128668 — Nicolas Grekas — 2025-09-10T16:17:20+00:00

URL: https://externals.io/message/128643#128668 · In reply to: #128655

Hi Tim


> Hello internals,
> > […]
>
> Thank you for the RFC. I have some comments:
>
> 1.
>
> I disagree with the phrasing that the RFC passed with a “narrow margin”.
> While it is technically true, that this is the narrowest margin for
> accepting an RFC, the necessary margins are already biased in favor of
> not accepting an RFC. That the RFC was accepted means that a significant
> majority of voters were in favor of the deprecation. I did not vote,
> since I did not have sufficient time to form an opinion on the RFC, but
> given the knowledge I've gained as part of the discussion I would now
> vote in favor of the RFC.
>

Jakub addressed that in a sub-thread.

2.
>
> The examples are biased. As an example, the initial “User” example has a
> serialization hook that is completely useless. The other examples try to
> replicate `__sleep()`'s broken behavior exactly, which seems to be a
> relevant requirement in the real world for only a minority of users.
>

The quantitative argument is not the only measure of the impact.
The RFC explains why - qualitatively - the RFC will have a significant
impact.
For the quantitative part, we can talk forever before agreeing.


> 3.
>
> Similarly, I believe that the RFC *overstates* the cost of the
> deprecation. From my experience a majority of serialization hooks will
> just unconditionally throw an exception to prevent serialization. The
> truth is probably somewhere in the middle.
>

I'm not sure why you talk about throwing hooks. Those are not concerned so
that's orthogonal to the points made.
From the small but not negligible share of the community I'm working with,
having both Doctrine and Symfony impacted means the impact will be
significant.
Add that to the fact the "fix" is risky (what the RFC explains), and this
will be a costly RFC for sure.
Note that as Jakub figured out in the latest example he added, not only
library-level codebases will need complex fixes: e.g. app-side user objects
that use __sleep/wakeup and that are put into a session storage will need
something as complex to address the deprecation without disrupting their
connected users.


> 4.
>
> The RFC correctly acknowleges that `__sleep()` is broken with regard to
> private properties, but at the same time claims that the deprecation
> does not fix a “correctness problem”, which is a contradiction.
>

I clarified this aspect in the RFC this way ("No technical urgency"
section):

>  Some consider that __sleep() is broken because it is incompatible with
nested private properties. Yet, this is more of a limitation rather than
something being broken: many use cases don't need access to private
properties and are just fine with the method. When one needs to overcome
this limitation, one can migrate to __serialize, on an opt-in basis.


> 5.
>
> The serialization mechanism is also a security sensitive part of the
> language, the fewer moving parts there are, the better. Security is part
> of the motivation for me.
>

Jakub addressed that in a sub-thread also.


> ----------------------
>
> That all said, as I've said before: I see that replacing __wakeup() by
> __unserialize() is non-trivial and I would be okay with deferring that
> one until we have some helper (e.g. `**s**et_mangled_object_vars`). But
> __sleep() can just go away.
>

We've added a note in the "Future scope" section, phrased like this:

> Consider dealing with __wakeup / __sleep separately as the impact might
be specific to each one

Cheers,
Nicolas

---

## #128670 — Sebastian Bergmann — 2025-09-11T06:33:50+00:00

URL: https://externals.io/message/128643#128670 · In reply to: #128665

Am 10.09.2025 um 15:23 schrieb Jakub Zelenka:
> If __sleep is used to serialize private properties (not all but just 
> some), then those property names are stored in the mangled format 
> ("\x00" . self::class . "\x00" prefix). It means to make it compatible in 
> __serialize, the application has to mangle property names - this can be 
> done either manually prefixing the name or using get_mangled_object_vars 
> and filter the mangled names. Alternatively it could use __serialize with 
> the new names but then it will need to deal with new and old (mangled) 
> formats in __unserialize. In any case it means that the users will be 
> required to deal with the mangled property name and get some understanding 
> of mangling.

On the off-chance this might be useful for somebody following this thread, 
this is what the prefixing approach looks like:

https://github.com/sebastianbergmann/php-code-coverage/blob/12.3.7/src/CodeCoverage.php#L92-L110

---

## #128671 — tim@bastelstu.be — 2025-09-11T06:57:40+00:00

URL: https://externals.io/message/128643#128671 · In reply to: #128667

Hi

Am 2025-09-10 17:39, schrieb Jakub Zelenka:
> > […]
> favor of __serialize() and __unserialize() passed (18–9), but only just 
> met
> the required 2/3 majority.
> 
> Hope it's better! :)

Thank you, the updated phrasing is better indeed. Factually stating that 
it just met the required majority (while stating the majority) is 
something different than saying it a close vote, which leaves room for 
ambiguity.

Best regards
Tim Düsterhus

---

## #128672 — tim@bastelstu.be — 2025-09-11T07:25:08+00:00

URL: https://externals.io/message/128643#128672 · In reply to: #128668

Hi

Am 2025-09-10 18:17, schrieb Nicolas Grekas:
> 2.
> > […]
> 
> The quantitative argument is not the only measure of the impact.
> The RFC explains why - qualitatively - the RFC will have a significant
> impact.
> For the quantitative part, we can talk forever before agreeing.

The product of both is the relevant metric. This appears to be a 
high-impact deprecation for a small amount of existing users. I believe 
that is less bad than a small-impact deprecation for a large amount of 
users. That's also why I voted against the driver-specific PDO 
constants, since the alternative is only available since the last 
version, giving folks little time for a natural migration. In this case, 
the alternative is available for quite some time already.

The impact to existing users is also not the only impact deprecating or 
not deprecating something will have. As an example, the RFC ignores the 
positive impact for folks that are newly writing some code by pointing 
them towards the “correct” solution. Something that is just in the 
documentation might as well not exist. Some of the documentation pages 
for functions I proposed to deprecate in past PHP versions are *full* of 
warnings (sometimes 3 of them), but folks *still* reach towards using 
those functions.

> > […]
> 
> I'm not sure why you talk about throwing hooks. Those are not concerned 
> so
> that's orthogonal to the points made.

If the majority of serialization hooks will just throw, this means that 
the original RFC did not affect them, which then raises the question of 
whether or not claims such as “many users” are accurate.

> > […]
> 
> I clarified this aspect in the RFC this way ("No technical urgency"
> section):
> 
> > […]
> nested private properties. Yet, this is more of a limitation rather 
> than
> something being broken: many use cases don't need access to private
> properties and are just fine with the method. When one needs to 
> overcome
> this limitation, one can migrate to __serialize, on an opt-in basis.

That is better, thank you. However “many use cases do not require 
private properties” is again making a claim that I'm not sure is 
supported by data. I don't have any better data, but:

- Using private properties is a best practice for encapsulation.
- When I serialize objects, I want to get the original data back out.

This suggests to me that supporting private properties properly cannot 
be an afterthought. Note that the issue with __sleep() is with private 
properties of parent and child classes. If inheritance doesn't get 
involved, __sleep() works just fine, but that case is also the case 
where migration to __serialize() is easy to do, since you the entire 
section (3) of the RFC doesn't apply.

In other words, the large migration complexity exists exactly in the 
cases that are not handled well by __sleep(), which I do not believe is 
coincidental! As a user you have a choice between continuing using 
__sleep() and breaking private properties or migrating to __serialize(), 
which will be painful once and then work will after that. To me the 
choice is clear: Doing the migration, since then I will not need to deal 
with the issues arising of broken inheritance for eternity.

> > […]
> 
> We've added a note in the "Future scope" section, phrased like this:
> 
> > […]
> be specific to each one

Thank you.

Best regards
Tim Düsterhus

---

## #128673 — Thomas Bley — 2025-09-11T09:39:00+00:00

URL: https://externals.io/message/128643#128673 · In reply to: #128670

> Sebastian Bergmann <sebastian@php.net> hat am 11.09.2025 08:33 CEST geschrieben:
> 
>  
> Am 10.09.2025 um 15:23 schrieb Jakub Zelenka:
> > […]
> 
> On the off-chance this might be useful for somebody following this thread, 
> this is what the prefixing approach looks like:
> 
> https://github.com/sebastianbergmann/php-code-coverage/blob/12.3.7/src/CodeCoverage.php#L92-L110

This serialize is currently not very optimal. E.g. Pest uses "--coverage-php" and in my setup SebastianBergmann\CodeCoverage\Report\PHP::process() then consumes gigabytes of ram, >500M on disk and >20s extra time to get the coverage report.

Regards
Thomas

---

## #128674 — Nicolas Grekas — 2025-09-11T16:51:55+00:00

URL: https://externals.io/message/128643#128674 · In reply to: #128659

Hi Daniel,

Thanks for the update.

Le lun. 8 sept. 2025 à 19:25, Daniel Scherzer <daniel.e.scherzer@gmail.com>
a écrit :

> On Mon, Sep 8, 2025 at 8:21 PM Nicolas Grekas <
> nicolas.grekas+php@gmail.com> wrote:
>
> > […]
>
> The PHP 8.5 RM team has discussed this internally, and arrived at the
> following. A full explanation of our reasoning follows.
>
> - Given the accepted RFC for deprecating `__sleep()` and `__wakeup()` in
> PHP 8.5, we should aim to merge the deprecation in time for PHP 8.5, i.e.
> before PHP-8.5 is branched on September 23.
> - If the RFC to switch the deprecation to a "soft deprecation" is
> accepted, the RM team is comfortable with landing a revert of the
> deprecation as long as the revert can land before RC2.
>
> Our reasoning is as follows ("hard deprecation" means the warnings, "soft
> deprecation" is just the documentation):
>
> 1. We cannot assume that the soft deprecation RFC will be accepted.
> However, if we wait until we know for certain that the RFC fails, it would
> be too late to *then* merge the hard deprecation. By our math, if the soft
> deprecation RFC had exactly 2 weeks of discussion and then 2 weeks of
> voting, the earliest it would close is October 4, with RC*2* being tagged
> October 7.
>
> 2. Since we cannot merge the hard deprecation after RC1, the hard
> deprecation either needs to go into PHP 8.5 before RC1, or be delayed until
> the next release. Since there was an RFC for doing the deprecation in PHP
> 8.5 that got accepted, 8.5 should be preferred.
>
> 3. Having a hard deprecation in PHP 8.5, and converting it to a soft
> deprecation in PHP 8.6 (or PHP 9.0, whatever is next), does not make sense.
> For the soft deprecation RFC to be meaningful, we would need to not have
> the hard deprecation warnings in PHP 8.5.
>
> 4. If the hard deprecation is implemented for 8.5 (per note 2) but the
> soft deprecation RFC is accepted, then (per note 3) we should remove the
> hard deprecation warnings from PHP 8.5. However, such a relatively large
> change should not be made too close to the GA release of PHP 8.5.0. Release
> candidates are meant to match the eventual release as closely as possible.
>
> 5. Given the minimum schedule outlined in note 1 above, there are a few
> days before the soft deprecation RFC could finish voting and when RC2 is
> packaged. This should be enough time to land a revert of the hard
> deprecation, given that a) the patch can be reviewed and approved before
> the RFC finishes, and b) the patch is likely to be just a revert of the
> original deprecation patches. By removing the warnings from RC2, community
> developers waiting to test the release candidates until after the warnings
> were removed can have 3 release candidates to do so.
>

The interesting thing with that approach is that all libs that do test
with php-src dev-master will see the deprecation, so at least some OSS
maintainers will work on addressing this as we speak.
This might give useful hints about the impact of the deprecation (like the
feedback from Sebastian on phpunit, followed by one from Thomas stating
this resulted in a perf issue).
On Symfony, we have 3 branches maintained: the next major is already free
from sleep/wakeup; the next minor has BC layers that look like the ones
presented in the RFC; and the next patch-level is not free from the
deprecation: we addressed throwing/internal/final cases and chose the
option to silence in the CI instead for the complex cases. The CI is still
not green: dependencies will have to be patched also. I've no idea how much
time this will take. But I know it's a significant effort - way more than
usual for a deprecation!

As a corollary to your message, I'm wondering what would be the earliest we
could open the vote?
Our policy on the topic says:

> There'd be a minimum of 2 weeks between when an RFC that touches the
> language is brought up on this list and when it's voted on is required.
> Other RFCs might use a smaller timeframe, but it should be at least a week.


Should it be one or two weeks?
The earlier the better for everyone I think (I don’t expect to convince Tim
either way, so from my side that part of the discussion is done. ;) )

Cheers,
Nicolas

---

## #128677 — tim@bastelstu.be — 2025-09-11T19:20:53+00:00

URL: https://externals.io/message/128643#128677 · In reply to: #128674

Hi


> As a corollary to your message, I'm wondering what would be the earliest we
> could open the vote?
> Our policy on the topic says:
> 
> > […]
> 
> 
> Should it be one or two weeks?

Clarifying this is part of my current policy RFC. The established 
consensus (and expectations from users) is at least 2 weeks of 
discussion for everything.

That would be Friday, September 19th 2025 17:54 Europe/Paris then.

Even when taking into account the expectation that changes to the RFC 
text requires additional discussion (my policy RFC is also formalizing 
that), I'd say that the changes you have made to the RFC are only 
clarification that do not change the actual proposal, which would be a 
minor change under the definition of my proposal.

Therefore I'd say that starting the vote at any point after the above 
mentioned time is strictly within policy.

> (I don’t expect to convince Tim
> either way, so from my side that part of the discussion is done. ;) )

I agree.

I'm also okay with the updated RFC text. While there are still some 
things that I believe could be presented differently (as I outlined in 
my email earlier today), it reasonable fairly represents the situation.

I still disagree with the proposal itself, of course :-)

Best regards
Tim Düsterhus

---

## #128690 — Hans Krentel — 2025-09-12T21:34:16+00:00

URL: https://externals.io/message/128643#128690 · In reply to: #128643

> Hello internals,
 > 
 > Following the discussion that started at
 > https://externals.io/message/128226#128456 I wrote this RFC to formalize
 > our consensus on the topic.
 > 
 > TL;DR, this is about converting the deprecation of __sleep and __wakeup 
to
 > a documentation-based soft deprecation:
 > https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup

That's very interesting! Didn't know it's possible to soft-deprecate in 
PHP.

And by chance if you know it: Where is the database of all 
soft-deprecations PHP has so far? Hypertext reference appreceated.

-- hakre

---

## #128710 — Nicolas Grekas — 2025-09-17T07:02:03+00:00

URL: https://externals.io/message/128643#128710 · In reply to: #128643

Hi all,

Hello internals,
>
> Following the discussion that started at
> https://externals.io/message/128226#128456 I wrote this RFC to formalize
> our consensus on the topic.
>
> TL;DR, this is about converting the deprecation of __sleep and __wakeup to
> a documentation-based soft deprecation:
> https://wiki.php.net/rfc/soft-deprecate-sleep-wakeup
>


The 2 weeks discussion period on this RFC is coming to an end without
significant activity anymore.
I therefore plan to start the vote on Saturday 20th.

Cheers,
Nicolas
