[PHP-DEV] [RFC] [VOTE] Deprecations for PHP 8.5

Hello internals,

As Tim announced a few days ago, I've opened the votes for the deprecations:

Please remember that the wiki is only capable to handle a single vote at a time,
so please submit each vote you intend on casting individually.

Best regards,

Gina P. Banyard

On Friday, 25 July 2025 at 13:56, Gina P. Banyard <internals@gpb.moe> wrote:

Hello internals,

As Tim announced a few days ago, I've opened the votes for the deprecations:
PHP: rfc:deprecations_php_8_5

Please remember that the wiki is only capable to handle a single vote at a time,
so please submit each vote you intend on casting individually.

Hello internals,

After two weeks of voting, I closed the votes of the "Deprecations for PHP 8.5" RFC at 19:45 UTC.

The following proposals have been accepted:

- Deprecate semicolon after case in switch statement (22 yay, 10 nay, 68.8%)
- Deprecate non-standard cast names (32 yay, 0 nay, 100%)
- Deprecate backticks as an alias for shell_exec (21 yay, 8 nay, 72.4%)
- Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay, 66.7%)
- Deprecate using values null as an array offset and when calling array_key_exists() (25 yay, 3 nay, 89.3%)
- Deprecate __debugInfo() returning null (22 yay, 5 nay, 81.5%)
- Deprecate constant redeclaration (31 yay, 0 nay, 100%)
- Deprecate closure binding issues (29 yay, 0 nay, 100%)
- Enact follow-up phase of the "Path to Saner Increment/Decrement operators" RFC (23 yay, 4 nay, 85.2%)
- Deprecate the report_memleaks INI directive (23 yay, 2 nay, 92.0%)
- Deprecate the register_argc_argv INI directive (27 yay, 0 nay, 100%)
- Remove disable_classes INI setting (26 yay, 0 nay, 100%)
- Deprecate Reflection*::setAccessible() (24 yay, 0 nay, 100%)
- Deprecate ReflectionClass::getConstant() for missing constants (25 yay, 0 nay, 100%)
- Deprecate ReflectionProperty::getDefaultValue() for properties without default values (21 yay, 2 nay, 89.5%)
- Deprecate ArrayObject and ArrayIterator with objects (26 yay, 0 nay, 100%)
- Deprecate SplObjectStorage::contains(), SplObjectStorage::attach(), and SplObjectStorage::detach() (17 yay, 2 nay, 89.5%)
- Deprecate passing spl_autoload_call() to spl_autoload_unregister() (23 yay, 0 nay, 100%)
- Deprecate the $exclude_disabled parameter of get_defined_functions() (23 yay, 0 nay, 100%)
- Deprecate passing null to readdir(), rewinddir(), and closedir() (24 yay, 3 nay, 88.9%)
- Deprecate passing string which are not one byte long to ord() (20 yay, 4 nay, 83.3%)
- Deprecate passing integers outside the interval [0, 255] to chr() (21 yay, 1 nay, 95.5%)
- Formally deprecate socket_set_timeout (22 yay, 0 nay, 100%)
- Deprecate the $http_response_header predefined variable (22 yay, 2 nay, 91.7%)
- [ODBC] Remove flags for building against specific drivers directly (16 yay, 0 nay, 100%)
- Remove support for older ODBC versions (15 yay, 0 nay, 100%)
- Deprecate PDO's 'uri:' scheme (22 yay, 0 nay, 100%)
- Deprecate driver specific PDO constants and methods (17 yay, 6 nay, 73.9%)
- Deprecate Pdo\Pgsql constants related to statement transaction state (17 yay, 0 nay, 100%)
- Deprecate finfo_close() (24 yay, 2 nay, 92.3%)
- Deprecate xml_parser_free() (22 yay, 2 nay, 91.7%)
- Deprecate curl_close() (23 yay, 3 nay, 88.5%)
- Deprecate curl_share_close() (23 yay, 3 nay, 88.5%)
- Deprecate imagedestroy() (23 yay, 2 nay, 92.0%)
- Deprecate key_length parameter of openssl_pkey_derive() (24 yay, 0 nay, 100%)
- Deprecate intl.error_level INI setting (22 yay, 0 nay, 100%)
- Formally deprecate mysqli_execute() (22 yay, 0 nay, 100%)
- Deprecate building ext/ldap against Oracle LDAP (19 yay, 0 nay, 100%)
- Deprecate the $context parameter for finfo_buffer() (24 yay, 0 nay, 100%)
- Deprecate DATE_RFC7231 and DateTimeInterface::RFC7231 (22 yay, 0 nay, 100%)

And the following proposals have been rejected:

- Deprecate attributes applying to multiple class properties/constants (5 yay, 19 nay, 20.8%)
- Deprecate ReflectionParameter::allowsNull() (9 yay, 10 nay, 47.4%)
- Deprecate non-canonical type names for settype() (8 yay, 10 nay, 44.4%)
- Deprecate FILTER_DEFAULT constant (12 yay, 10 nay, 54.5%)
- Make $filter parameter mandatory for filter_*() functions (9 yay, 10 nay, 47.4%)
- Deprecate PDO::ERRMODE_WARNING error mode (8 yay, 12 nay, 40.0%)

Thank you to everyone that has voted and participated in the discussions.

Best regards,

Gina P. Banyard

Le ven. 8 août 2025 à 22:10, Gina P. Banyard internals@gpb.moe a écrit :

On Friday, 25 July 2025 at 13:56, Gina P. Banyard internals@gpb.moe wrote:

Hello internals,

As Tim announced a few days ago, I’ve opened the votes for the deprecations:
https://wiki.php.net/rfc/deprecations_php_8_5

Please remember that the wiki is only capable to handle a single vote at a time,
so please submit each vote you intend on casting individually.

Hello internals,

After two weeks of voting, I closed the votes of the “Deprecations for PHP 8.5” RFC at 19:45 UTC.

The following proposals have been accepted:

  • Deprecate semicolon after case in switch statement (22 yay, 10 nay, 68.8%)
  • Deprecate non-standard cast names (32 yay, 0 nay, 100%)
  • Deprecate backticks as an alias for shell_exec (21 yay, 8 nay, 72.4%)
  • Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay, 66.7%)
  • Deprecate using values null as an array offset and when calling array_key_exists() (25 yay, 3 nay, 89.3%)
  • Deprecate __debugInfo() returning null (22 yay, 5 nay, 81.5%)
  • Deprecate constant redeclaration (31 yay, 0 nay, 100%)
  • Deprecate closure binding issues (29 yay, 0 nay, 100%)
  • Enact follow-up phase of the “Path to Saner Increment/Decrement operators” RFC (23 yay, 4 nay, 85.2%)
  • Deprecate the report_memleaks INI directive (23 yay, 2 nay, 92.0%)
  • Deprecate the register_argc_argv INI directive (27 yay, 0 nay, 100%)
  • Remove disable_classes INI setting (26 yay, 0 nay, 100%)
  • Deprecate Reflection*::setAccessible() (24 yay, 0 nay, 100%)
  • Deprecate ReflectionClass::getConstant() for missing constants (25 yay, 0 nay, 100%)
  • Deprecate ReflectionProperty::getDefaultValue() for properties without default values (21 yay, 2 nay, 89.5%)
  • Deprecate ArrayObject and ArrayIterator with objects (26 yay, 0 nay, 100%)
  • Deprecate SplObjectStorage::contains(), SplObjectStorage::attach(), and SplObjectStorage::detach() (17 yay, 2 nay, 89.5%)
  • Deprecate passing spl_autoload_call() to spl_autoload_unregister() (23 yay, 0 nay, 100%)
  • Deprecate the $exclude_disabled parameter of get_defined_functions() (23 yay, 0 nay, 100%)
  • Deprecate passing null to readdir(), rewinddir(), and closedir() (24 yay, 3 nay, 88.9%)
  • Deprecate passing string which are not one byte long to ord() (20 yay, 4 nay, 83.3%)
  • Deprecate passing integers outside the interval [0, 255] to chr() (21 yay, 1 nay, 95.5%)
  • Formally deprecate socket_set_timeout (22 yay, 0 nay, 100%)
  • Deprecate the $http_response_header predefined variable (22 yay, 2 nay, 91.7%)
  • [ODBC] Remove flags for building against specific drivers directly (16 yay, 0 nay, 100%)
  • Remove support for older ODBC versions (15 yay, 0 nay, 100%)
  • Deprecate PDO’s ‘uri:’ scheme (22 yay, 0 nay, 100%)
  • Deprecate driver specific PDO constants and methods (17 yay, 6 nay, 73.9%)
  • Deprecate Pdo\Pgsql constants related to statement transaction state (17 yay, 0 nay, 100%)
  • Deprecate finfo_close() (24 yay, 2 nay, 92.3%)
  • Deprecate xml_parser_free() (22 yay, 2 nay, 91.7%)
  • Deprecate curl_close() (23 yay, 3 nay, 88.5%)
  • Deprecate curl_share_close() (23 yay, 3 nay, 88.5%)
  • Deprecate imagedestroy() (23 yay, 2 nay, 92.0%)
  • Deprecate key_length parameter of openssl_pkey_derive() (24 yay, 0 nay, 100%)
  • Deprecate intl.error_level INI setting (22 yay, 0 nay, 100%)
  • Formally deprecate mysqli_execute() (22 yay, 0 nay, 100%)
  • Deprecate building ext/ldap against Oracle LDAP (19 yay, 0 nay, 100%)
  • Deprecate the $context parameter for finfo_buffer() (24 yay, 0 nay, 100%)
  • Deprecate DATE_RFC7231 and DateTimeInterface::RFC7231 (22 yay, 0 nay, 100%)

And the following proposals have been rejected:

  • Deprecate attributes applying to multiple class properties/constants (5 yay, 19 nay, 20.8%)
  • Deprecate ReflectionParameter::allowsNull() (9 yay, 10 nay, 47.4%)
  • Deprecate non-canonical type names for settype() (8 yay, 10 nay, 44.4%)
  • Deprecate FILTER_DEFAULT constant (12 yay, 10 nay, 54.5%)
  • Make $filter parameter mandatory for filter_*() functions (9 yay, 10 nay, 47.4%)
  • Deprecate PDO::ERRMODE_WARNING error mode (8 yay, 12 nay, 40.0%)

Thank you to everyone that has voted and participated in the discussions.

Best regards,

Gina P. Banyard

I’d like to raise some concerns about the decision to deprecate __sleep() and __wakeup().

While I understand the intention behind moving toward __serialize() and __unserialize(), in practice the migration path is often non-trivial. For example, in Symfony’s codebase there are numerous cases where switching requires deep knowledge of PHP’s serialization format to maintain compatibility with existing payloads. This is essential so that updated applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that __sleep() and __wakeup() have historically worked well for these use cases. I’m concerned that the practical cost to the community may outweigh the benefits, particularly since the rationale for removal seems, at least from a user’s perspective, debatable.

I don’t know if there is room to reconsider the deprecation, but I wanted to share this perspective from the field.

Cheers,
Nicolas

On Wed, Aug 13, 2025 at 11:03 AM Nicolas Grekas <nicolas.grekas+php@gmail.com> wrote:

Le ven. 8 août 2025 à 22:10, Gina P. Banyard internals@gpb.moe a écrit :

On Friday, 25 July 2025 at 13:56, Gina P. Banyard internals@gpb.moe wrote:

Hello internals,

As Tim announced a few days ago, I’ve opened the votes for the deprecations:
https://wiki.php.net/rfc/deprecations_php_8_5

Please remember that the wiki is only capable to handle a single vote at a time,
so please submit each vote you intend on casting individually.

Hello internals,

After two weeks of voting, I closed the votes of the “Deprecations for PHP 8.5” RFC at 19:45 UTC.

The following proposals have been accepted:

  • Deprecate semicolon after case in switch statement (22 yay, 10 nay, 68.8%)
  • Deprecate non-standard cast names (32 yay, 0 nay, 100%)
  • Deprecate backticks as an alias for shell_exec (21 yay, 8 nay, 72.4%)
  • Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay, 66.7%)
  • Deprecate using values null as an array offset and when calling array_key_exists() (25 yay, 3 nay, 89.3%)
  • Deprecate __debugInfo() returning null (22 yay, 5 nay, 81.5%)
  • Deprecate constant redeclaration (31 yay, 0 nay, 100%)
  • Deprecate closure binding issues (29 yay, 0 nay, 100%)
  • Enact follow-up phase of the “Path to Saner Increment/Decrement operators” RFC (23 yay, 4 nay, 85.2%)
  • Deprecate the report_memleaks INI directive (23 yay, 2 nay, 92.0%)
  • Deprecate the register_argc_argv INI directive (27 yay, 0 nay, 100%)
  • Remove disable_classes INI setting (26 yay, 0 nay, 100%)
  • Deprecate Reflection*::setAccessible() (24 yay, 0 nay, 100%)
  • Deprecate ReflectionClass::getConstant() for missing constants (25 yay, 0 nay, 100%)
  • Deprecate ReflectionProperty::getDefaultValue() for properties without default values (21 yay, 2 nay, 89.5%)
  • Deprecate ArrayObject and ArrayIterator with objects (26 yay, 0 nay, 100%)
  • Deprecate SplObjectStorage::contains(), SplObjectStorage::attach(), and SplObjectStorage::detach() (17 yay, 2 nay, 89.5%)
  • Deprecate passing spl_autoload_call() to spl_autoload_unregister() (23 yay, 0 nay, 100%)
  • Deprecate the $exclude_disabled parameter of get_defined_functions() (23 yay, 0 nay, 100%)
  • Deprecate passing null to readdir(), rewinddir(), and closedir() (24 yay, 3 nay, 88.9%)
  • Deprecate passing string which are not one byte long to ord() (20 yay, 4 nay, 83.3%)
  • Deprecate passing integers outside the interval [0, 255] to chr() (21 yay, 1 nay, 95.5%)
  • Formally deprecate socket_set_timeout (22 yay, 0 nay, 100%)
  • Deprecate the $http_response_header predefined variable (22 yay, 2 nay, 91.7%)
  • [ODBC] Remove flags for building against specific drivers directly (16 yay, 0 nay, 100%)
  • Remove support for older ODBC versions (15 yay, 0 nay, 100%)
  • Deprecate PDO’s ‘uri:’ scheme (22 yay, 0 nay, 100%)
  • Deprecate driver specific PDO constants and methods (17 yay, 6 nay, 73.9%)
  • Deprecate Pdo\Pgsql constants related to statement transaction state (17 yay, 0 nay, 100%)
  • Deprecate finfo_close() (24 yay, 2 nay, 92.3%)
  • Deprecate xml_parser_free() (22 yay, 2 nay, 91.7%)
  • Deprecate curl_close() (23 yay, 3 nay, 88.5%)
  • Deprecate curl_share_close() (23 yay, 3 nay, 88.5%)
  • Deprecate imagedestroy() (23 yay, 2 nay, 92.0%)
  • Deprecate key_length parameter of openssl_pkey_derive() (24 yay, 0 nay, 100%)
  • Deprecate intl.error_level INI setting (22 yay, 0 nay, 100%)
  • Formally deprecate mysqli_execute() (22 yay, 0 nay, 100%)
  • Deprecate building ext/ldap against Oracle LDAP (19 yay, 0 nay, 100%)
  • Deprecate the $context parameter for finfo_buffer() (24 yay, 0 nay, 100%)
  • Deprecate DATE_RFC7231 and DateTimeInterface::RFC7231 (22 yay, 0 nay, 100%)

And the following proposals have been rejected:

  • Deprecate attributes applying to multiple class properties/constants (5 yay, 19 nay, 20.8%)
  • Deprecate ReflectionParameter::allowsNull() (9 yay, 10 nay, 47.4%)
  • Deprecate non-canonical type names for settype() (8 yay, 10 nay, 44.4%)
  • Deprecate FILTER_DEFAULT constant (12 yay, 10 nay, 54.5%)
  • Make $filter parameter mandatory for filter_*() functions (9 yay, 10 nay, 47.4%)
  • Deprecate PDO::ERRMODE_WARNING error mode (8 yay, 12 nay, 40.0%)

Thank you to everyone that has voted and participated in the discussions.

Best regards,

Gina P. Banyard

I’d like to raise some concerns about the decision to deprecate __sleep() and __wakeup().

While I understand the intention behind moving toward __serialize() and __unserialize(), in practice the migration path is often non-trivial. For example, in Symfony’s codebase there are numerous cases where switching requires deep knowledge of PHP’s serialization format to maintain compatibility with existing payloads. This is essential so that updated applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that __sleep() and __wakeup() have historically worked well for these use cases. I’m concerned that the practical cost to the community may outweigh the benefits, particularly since the rationale for removal seems, at least from a user’s perspective, debatable.

Fully agree and this is exactly what I noted in https://github.com/php/php-src/pull/19435 . I think this RFC was very poor in showing the effort that is needed for migration as it was represented like a trivial thing.

Kind regards

Jakub

On 13.08.2025 at 11:00, Nicolas Grekas wrote:

Le ven. 8 août 2025 à 22:10, Gina P. Banyard <internals@gpb.moe> a écrit :

The following proposals have been accepted:

- Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay,
66.7%)

I’d like to raise some concerns about the decision to deprecate __sleep()
and __wakeup().

While I understand the intention behind moving toward __serialize() and
__unserialize(), in practice the migration path is often non-trivial. For
example, in Symfony’s codebase there are numerous cases where switching
requires deep knowledge of PHP’s serialization format to maintain
compatibility with existing payloads. This is essential so that updated
applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that
__sleep() and __wakeup() have historically worked well for these use cases.
I’m concerned that the practical cost to the community may outweigh the
benefits, particularly since the rationale for removal seems, at least from
a user’s perspective, debatable.

I don’t know if there is room to reconsider the deprecation, but I wanted
to share this perspective from the field.

Frankly, I do not quite understand why it has even been suggested (so
early) to deprecate __sleep()/__wakeup(). Even the New custom object
serialization mechanism RFC[1] acknowledged that this mechanism is *not*
fundamentally broken, but only somewhat limited, and that:

| There is no particular pressing need to phase out __sleep() and
| __wakeup().

However, I'm afraid that ship has sailed.

[1] <PHP: rfc:custom_object_serialization;

Christoph

On Wed 13 Aug 2025, 13:44 Christoph M. Becker, <cmbecker69@gmx.de> wrote:

On 13.08.2025 at 11:00, Nicolas Grekas wrote:

Le ven. 8 août 2025 à 22:10, Gina P. Banyard internals@gpb.moe a écrit :

The following proposals have been accepted:

  • Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay,
    66.7%)

I’d like to raise some concerns about the decision to deprecate __sleep()
and __wakeup().

While I understand the intention behind moving toward __serialize() and
__unserialize(), in practice the migration path is often non-trivial. For
example, in Symfony’s codebase there are numerous cases where switching
requires deep knowledge of PHP’s serialization format to maintain
compatibility with existing payloads. This is essential so that updated
applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that
__sleep() and __wakeup() have historically worked well for these use cases.
I’m concerned that the practical cost to the community may outweigh the
benefits, particularly since the rationale for removal seems, at least from
a user’s perspective, debatable.

I don’t know if there is room to reconsider the deprecation, but I wanted
to share this perspective from the field.

Frankly, I do not quite understand why it has even been suggested (so
early) to deprecate __sleep()/__wakeup(). Even the New custom object
serialization mechanism RFC[1] acknowledged that this mechanism is not
fundamentally broken, but only somewhat limited, and that:

| There is no particular pressing need to phase out __sleep() and
| __wakeup().

However, I’m afraid that ship has sailed.

[1] <https://wiki.php.net/rfc/custom_object_serialization>

Christoph

Can we propose to undeprecate it before the feature freeze?

Le mer. 13 août 2025 à 12:47, Kamil Tekiela <tekiela246@gmail.com> a écrit :

On Wed 13 Aug 2025, 13:44 Christoph M. Becker, <cmbecker69@gmx.de> wrote:

On 13.08.2025 at 11:00, Nicolas Grekas wrote:

Le ven. 8 août 2025 à 22:10, Gina P. Banyard internals@gpb.moe a écrit :

The following proposals have been accepted:

  • Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay,
    66.7%)

I’d like to raise some concerns about the decision to deprecate __sleep()
and __wakeup().

While I understand the intention behind moving toward __serialize() and
__unserialize(), in practice the migration path is often non-trivial. For
example, in Symfony’s codebase there are numerous cases where switching
requires deep knowledge of PHP’s serialization format to maintain
compatibility with existing payloads. This is essential so that updated
applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that
__sleep() and __wakeup() have historically worked well for these use cases.
I’m concerned that the practical cost to the community may outweigh the
benefits, particularly since the rationale for removal seems, at least from
a user’s perspective, debatable.

I don’t know if there is room to reconsider the deprecation, but I wanted
to share this perspective from the field.

Frankly, I do not quite understand why it has even been suggested (so
early) to deprecate __sleep()/__wakeup(). Even the New custom object
serialization mechanism RFC[1] acknowledged that this mechanism is not
fundamentally broken, but only somewhat limited, and that:

| There is no particular pressing need to phase out __sleep() and
| __wakeup().

However, I’m afraid that ship has sailed.

[1] <https://wiki.php.net/rfc/custom_object_serialization>

Christoph

Can we propose to undeprecate it before the feature freeze?

I wish we had some process to revert that decision. Now is the less costly time to do it, even if it’s already late.
The discussion period failed to raise the points made by Jakub in the PR (https://github.com/php/php-src/pull/19435) and failed a serious impact analysis IMHO.
This should be enough to raise a flag and allow us to reconsider.
I wonder if people that voted in favor of deprecating __sleep/wakeup would still vote the same now?

Nicolas

Hi

On 8/13/25 13:58, Nicolas Grekas wrote:

I wish we had some process to revert that decision. Now is the less costly
time to do it, even if it's already late.

There is always the option of ”not implementing” the decision. Reverting would mean another RFC that would also require a 2/3 majority.

The discussion period failed to raise the points made by Jakub in the PR (
Zend: Deprecate __sleep() and __wakeup() by Girgias · Pull Request #19435 · php/php-src · GitHub) and failed a serious impact
analysis IMHO.
This should be enough to raise a flag and allow us to reconsider.
I wonder if people that voted in favor of deprecating __sleep/wakeup would
still vote the same now?

I already participated in the PR discussion and having slept over it, I think it would be helpful to consider both __sleep() and __wakeup() separately in this discussion of whether or not to actually follow through with doing the deprecation.

As I've mentioned in the PR, `__sleep()` is actually broken when inheritance is involved and there's also a trivial way to implement `__serialize()` while preserving compatibility:

     public function __serialize() {
         return get_mangled_object_vars($this);
     }

So while this one might result in some amount of migration work, it's reasonably easy to do.

`__wakeup()` on the other hand is not broken and migrating to `__unserialize()` is non-trivial.

So deprecating `__sleep()` with PHP 8.5 still makes sense to me. For `__wakeup()` I don't have a strong opinion either way and I've also intentionally abstained from voting on this deprecation.

Best regards
Tim Düsterhus

Hi all,

Can we propose to undeprecate it before the feature freeze?

When one part of the Attributes v2 RFC did not work out as some wanted, there was a re-vote:

- PHP: rfc:attributes_v2
- PHP: rfc:shorter_attribute_syntax_change

So there's precedent for this kind of thing.

-- pmj

Le mer. 13 août 2025 à 14:33, Tim Düsterhus <tim@bastelstu.be> a écrit :

Hi

On 8/13/25 13:58, Nicolas Grekas wrote:

I wish we had some process to revert that decision. Now is the less costly
time to do it, even if it’s already late.

There is always the option of ”not implementing” the decision. Reverting
would mean another RFC that would also require a 2/3 majority.

I’m happy to do it this way if that’s the consensus.

The discussion period failed to raise the points made by Jakub in the PR (
https://github.com/php/php-src/pull/19435) and failed a serious impact
analysis IMHO.
This should be enough to raise a flag and allow us to reconsider.
I wonder if people that voted in favor of deprecating __sleep/wakeup would
still vote the same now?

I already participated in the PR discussion and having slept over it, I
think it would be helpful to consider both __sleep() and __wakeup()
separately in this discussion of whether or not to actually follow
through with doing the deprecation.

As I’ve mentioned in the PR, __sleep() is actually broken when
inheritance is involved and there’s also a trivial way to implement
__serialize() while preserving compatibility:

public function __serialize() {
return get_mangled_object_vars($this);
}

Well, the way to introduce __serialize while maintaining compatibility with both child classes and existing payloads is to copy/paste the same boilerplate over and over:

public function __serialize(): array
{
$data = ;
foreach ($this->__sleep() as $key) {
$data[$key] = $this->$key;
}
return $data;
}

And then, this has exactly the same issue regarding private properties, without any better way since this has to call __sleep to account for child classes.
This is just moving the concern elsewhere without any benefit.
On their side, child classes that do have an issue with private properties can already implement __serialize on their side, there’s nothing to fix here: __sleep works well, and there’s already an upgrade path when it’s not enough.

So while this one might result in some amount of migration work, it’s
reasonably easy to do.

__wakeup() on the other hand is not broken and migrating to
__unserialize() is non-trivial.

So deprecating __sleep() with PHP 8.5 still makes sense to me. For
__wakeup() I don’t have a strong opinion either way and I’ve also
intentionally abstained from voting on this deprecation.

implementing __unserialize to satisfy a proper upgrade path for payload and child classes might be done this way:

public function __unserialize(array $data): void
{
foreach ($data as $key => $value) {
$this->{(“\0” === $key[0] ?? ‘’) ? substr($key, 1 + strrpos($key, “\0”)) : $key} = $value;
}
$this->__wakeup();
}

Again, this doesn’t work with private properties.

The previous code was better and safer, and contained less boilerplate.

I made a draft PR for SYmfony here: https://github.com/symfony/symfony/pull/61407
I’m not sure the implementation is correct yet.
That’s just to show the kind of impact this could have.

Deprecating only sleep and not wakeup would at least fix the complexity of the __unserialize replacement.
But then, this would fail the purpose of the RFC, which was to get rid of sleep/wakeup altogether.

This deprecation is a net loss on every aspect.

Nicolas

Le mer. 13 août 2025 à 17:34, Nicolas Grekas <nicolas.grekas+php@gmail.com> a écrit :

Le mer. 13 août 2025 à 14:33, Tim Düsterhus <tim@bastelstu.be> a écrit :

Hi

On 8/13/25 13:58, Nicolas Grekas wrote:

I wish we had some process to revert that decision. Now is the less costly
time to do it, even if it’s already late.

There is always the option of ”not implementing” the decision. Reverting
would mean another RFC that would also require a 2/3 majority.

I’m happy to do it this way if that’s the consensus.

The discussion period failed to raise the points made by Jakub in the PR (
https://github.com/php/php-src/pull/19435) and failed a serious impact
analysis IMHO.
This should be enough to raise a flag and allow us to reconsider.
I wonder if people that voted in favor of deprecating __sleep/wakeup would
still vote the same now?

I already participated in the PR discussion and having slept over it, I
think it would be helpful to consider both __sleep() and __wakeup()
separately in this discussion of whether or not to actually follow
through with doing the deprecation.

As I’ve mentioned in the PR, __sleep() is actually broken when
inheritance is involved and there’s also a trivial way to implement
__serialize() while preserving compatibility:

public function __serialize() {
return get_mangled_object_vars($this);
}

Well, the way to introduce __serialize while maintaining compatibility with both child classes and existing payloads is to copy/paste the same boilerplate over and over:

public function __serialize(): array
{
$data = ;
foreach ($this->__sleep() as $key) {
$data[$key] = $this->$key;
}
return $data;
}

And then, this has exactly the same issue regarding private properties, without any better way since this has to call __sleep to account for child classes.
This is just moving the concern elsewhere without any benefit.
On their side, child classes that do have an issue with private properties can already implement __serialize on their side, there’s nothing to fix here: __sleep works well, and there’s already an upgrade path when it’s not enough.

So while this one might result in some amount of migration work, it’s
reasonably easy to do.

__wakeup() on the other hand is not broken and migrating to
__unserialize() is non-trivial.

So deprecating __sleep() with PHP 8.5 still makes sense to me. For
__wakeup() I don’t have a strong opinion either way and I’ve also
intentionally abstained from voting on this deprecation.

implementing __unserialize to satisfy a proper upgrade path for payload and child classes might be done this way:

public function __unserialize(array $data): void
{
foreach ($data as $key => $value) {
$this->{(“\0” === $key[0] ?? ‘’) ? substr($key, 1 + strrpos($key, “\0”)) : $key} = $value;
}
$this->__wakeup();
}

Again, this doesn’t work with private properties.

The previous code was better and safer, and contained less boilerplate.

I made a draft PR for SYmfony here: https://github.com/symfony/symfony/pull/61407
I’m not sure the implementation is correct yet.
That’s just to show the kind of impact this could have.

Deprecating only sleep and not wakeup would at least fix the complexity of the __unserialize replacement.
But then, this would fail the purpose of the RFC, which was to get rid of sleep/wakeup altogether.

This deprecation is a net loss on every aspect.

Nicolas

Here is the result of my investigation; the kind code that everybody that cares about FC/BC for child classes and payloads will have to use (above PR is up to date):

public function __serialize(): array
{
$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;
}
public function __unserialize(array $data): void
{
\Closure::bind(function ($data) {
foreach ($data as $key => $value) {
$this->{(“\0” === $key[0] ?? ‘’) ? substr($key, 1 + strrpos($key, “\0”)) : $key} = $value;
}
$this->__wakeup();
}, $this, static::class)($data);
}

On Wed, Aug 13, 2025, at 11:36 AM, Nicolas Grekas wrote:

Le mer. 13 août 2025 à 17:34, Nicolas Grekas
<nicolas.grekas+php@gmail.com <mailto:nicolas.grekas%2Bphp@gmail.com>>
a écrit :

Le mer. 13 août 2025 à 14:33, Tim Düsterhus <tim@bastelstu.be> a écrit :

Hi

On 8/13/25 13:58, Nicolas Grekas wrote:
> I wish we had some process to revert that decision. Now is the less costly
> time to do it, even if it's already late.

There is always the option of ”not implementing” the decision. Reverting
would mean another RFC that would also require a 2/3 majority.

I'm happy to do it this way if that's the consensus.

> The discussion period failed to raise the points made by Jakub in the PR (
> Zend: Deprecate __sleep() and __wakeup() by Girgias · Pull Request #19435 · php/php-src · GitHub) and failed a serious impact
> analysis IMHO.
> This should be enough to raise a flag and allow us to reconsider.
> I wonder if people that voted in favor of deprecating __sleep/wakeup would
> still vote the same now?

I already participated in the PR discussion and having slept over it, I
think it would be helpful to consider both __sleep() and __wakeup()
separately in this discussion of whether or not to actually follow
through with doing the deprecation.

As I've mentioned in the PR, `__sleep()` is actually broken when
inheritance is involved and there's also a trivial way to implement
`__serialize()` while preserving compatibility:

     public function __serialize() {
         return get_mangled_object_vars($this);
     }

Well, the way to introduce __serialize while maintaining compatibility with both child classes and existing payloads is to copy/paste the same boilerplate over and over:

    public function __serialize(): array
    {
        $data = ;
        foreach ($this->__sleep() as $key) {
            $data[$key] = $this->$key;
        }
        return $data;
    }

And then, this has exactly the same issue regarding private properties, without any better way since this has to call __sleep to account for child classes.
This is just moving the concern elsewhere without any benefit.
On their side, child classes that do have an issue with private properties can already implement __serialize on their side, there's nothing to fix here: __sleep works well, and there's already an upgrade path when it's not enough.

So while this one might result in some amount of migration work, it's
reasonably easy to do.

`__wakeup()` on the other hand is not broken and migrating to
`__unserialize()` is non-trivial.

So deprecating `__sleep()` with PHP 8.5 still makes sense to me. For
`__wakeup()` I don't have a strong opinion either way and I've also
intentionally abstained from voting on this deprecation.

implementing __unserialize to satisfy a proper upgrade path for payload and child classes might be done this way:

    public function __unserialize(array $data): void
    {
        foreach ($data as $key => $value) {
            $this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;
        }
        $this->__wakeup();
    }

Again, this doesn't work with private properties.

The previous code was better and safer, and contained less boilerplate.

I made a draft PR for SYmfony here: Account for PHP 8.5 deprecating __sleep()/__wakeup() by nicolas-grekas · Pull Request #61407 · symfony/symfony · GitHub
I'm not sure the implementation is correct yet.
That's just to show the kind of impact this could have.

Deprecating only sleep and not wakeup would at least fix the complexity of the __unserialize replacement.
But then, this would fail the purpose of the RFC, which was to get rid of sleep/wakeup altogether.

This deprecation is a net loss on every aspect.

Nicolas

Here is the result of my investigation; the kind code that everybody
that cares about FC/BC for child classes and payloads will have to use
(above PR is up to date):

    public function __serialize(): array
    {
        $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;
    }
    public function __unserialize(array $data): void
    {
        \Closure::bind(function ($data) {
            foreach ($data as $key => $value) {
                $this->{("\0" === $key[0] ?? '') ? substr($key, 1 +
strrpos($key, "\0")) : $key} = $value;
            }
            $this->__wakeup();
        }, $this, static::class)($data);
    }

Eew. :slight_smile:

I support the goal of having only one serialization process for devs to think about, but it does need to have a clear and graceful transition for existing code. The above code does not strike me as "clear and graceful transition."

From the RFC:

Having multiple serializations methods which can be superseded by newer methods is somewhat confusing and add unnecessary complexity to the language.

I agree, which is why I voted Yes on that part.

Because the __serialize()/__unserialize() mechanism is a straight up improvement over __sleep()/__wakeup() we propose to deprecate the latter in favour of the former.

This claim now appears to be incorrect, given Nicolas' investigation. (Ie, it's not a straight up improvement, nor a drop-in replacement.)

I would be in favor of holding off implementing this deprecation until a better transition process is found, and/or an RFC to reverse it. (I defer to the RMs on the process they want to follow.)

(And I think this does lend still more weight to Juliette's frequent request for more robust impact analysis for deprecations. Not because deprecations are bad, but because we should know what the impact is so we know how to mitigate it effectively.)

--Larry Garfield

On Wed, August 13, 2025 at 10:54 Larry Garfield wrote:

(And I think this does lend still more weight to Juliette's frequent request for more
robust impact analysis for deprecations. Not because deprecations are bad, but because
we should know what the impact is so we know how to mitigate it effectively.)

I analyzed the top 1500 Composer packages to find and categorize usages of the
`__sleep` and `__wakeup` methods. There are a total of 250 `__sleep` methods
and 259 `__wakeup` methods in these packages (509 total).

Of these, 108 are empty methods containing no code. Most of these are stubs
in the jetbrains\phpstorm-stubs package.

Another 152 of the methods contain only a single throw statement.

This leaves 160 `__sleep` methods and 89 `__wakeup` methods (249 total) which do
something else. 150 of these (over 60%) exist in just 9 packages:

* doctrine\orm - 14
* drupal\core - 38
* laminas\laminas-server - 7
* maatwebsite\excel - 7
* magento\zend-db - 7
* pdepend\pdepend - 31
* roots\wordpress-no-content - 6
* symfony\mime - 8
* symfony\symfony - 32

Outside of the above packages, `__sleep` and `__wakup` methods generally seem to
be few and far between.

I created a Google Sheet to view the per-package statistics:

The raw code for each `__sleep` and `__wakeup` method can be viewed here:

Kind regards,
Theodore

Hi,

Il 13/08/2025 18:54, Larry Garfield ha scritto:

I would be in favor of holding off implementing this deprecation until a better transition process is found, and/or an RFC to reverse it. (I defer to the RMs on the process they want to follow.)

(And I think this does lend still more weight to Juliette's frequent request for more robust impact analysis for deprecations. Not because deprecations are bad, but because we should know what the impact is so we know how to mitigate it effectively.)

+1

Cheers
--
Matteo

On Wed, August 13, 2025 at 16:20 Theodore Brown wrote:

I analyzed the top 1500 Composer packages to find and categorize usages of the
`__sleep` and `__wakeup` methods. There are a total of 250 `__sleep` methods
and 259 `__wakeup` methods in these packages (509 total).

Of these, 108 are empty methods containing no code. Most of these are stubs
in the jetbrains\phpstorm-stubs package.

Another 152 of the methods contain only a single throw statement.

This leaves 160 `__sleep` methods and 89 `__wakeup` methods (249 total) which do
something else. 150 of these (over 60%) exist in just 9 packages:

* doctrine\orm - 14
* drupal\core - 38
* laminas\laminas-server - 7
* maatwebsite\excel - 7
* magento\zend-db - 7
* pdepend\pdepend - 31
* roots\wordpress-no-content - 6
* symfony\mime - 8
* symfony\symfony - 32

Outside of the above packages, `__sleep` and `__wakup` methods generally seem to
be few and far between.

I created a Google Sheet to view the per-package statistics:
__sleep and __wakeup usages in top 1500 PHP packages, August 2025 - Google Spreadsheets

The raw code for each `__sleep` and `__wakeup` method can be viewed here:
PHP 8.5 syntax deprecations · GitHub

Update: it looks like nearly all the Symfony usages have already been fixed for Symfony 8.

I re-downloaded and analyzed the top 1500 packages again this afternoon, and now there
are a total of 159 `__sleep` methods and 207 `__wakeup` methods in 65 distinct packages,
a significant drop from when I did the analysis yesterday.

107 of the methods are empty, and 65 only contain a single throw statement.
Over 62% of the remaining methods exist in just 9 packages:

* doctrine\orm - 14
* drupal\core - 36
* johnpbloch\wordpress-core - 6
* laminas\laminas-server - 7
* maatwebsite\excel - 7
* magento\zend-db - 6
* pdepend\pdepend - 32
* swiftmailer\swiftmailer - 7
* typo3\cms-extbase - 6

I updated the above gist and Google Sheet links with the data from today.

Kind regards,
Theodore

On Wednesday, 13 August 2025 at 12:47, Kamil Tekiela <tekiela246@gmail.com> wrote:

On Wed 13 Aug 2025, 13:44 Christoph M. Becker, <cmbecker69@gmx.de> wrote:

On 13.08.2025 at 11:00, Nicolas Grekas wrote:

Le ven. 8 août 2025 à 22:10, Gina P. Banyard <internals@gpb.moe> a écrit :

The following proposals have been accepted:

- Deprecate the __sleep() and __wakeup() magic methods (18 yay, 9 nay,
66.7%)

I’d like to raise some concerns about the decision to deprecate __sleep()
and __wakeup().

While I understand the intention behind moving toward __serialize() and
__unserialize(), in practice the migration path is often non-trivial. For
example, in Symfony’s codebase there are numerous cases where switching
requires deep knowledge of PHP’s serialization format to maintain
compatibility with existing payloads. This is essential so that updated
applications can still communicate with older versions.

For many projects, this will be a significant burden, especially given that
__sleep() and __wakeup() have historically worked well for these use cases.
I’m concerned that the practical cost to the community may outweigh the
benefits, particularly since the rationale for removal seems, at least from
a user’s perspective, debatable.

I don’t know if there is room to reconsider the deprecation, but I wanted
to share this perspective from the field.

Frankly, I do not quite understand why it has even been suggested (so
early) to deprecate __sleep()/__wakeup(). Even the New custom object
serialization mechanism RFC[1] acknowledged that this mechanism is *not*
fundamentally broken, but only somewhat limited, and that:

| There is no particular pressing need to phase out __sleep() and
| __wakeup().

However, I'm afraid that ship has sailed.

[1] <https://wiki.php.net/rfc/custom_object_serialization&gt;

Christoph

Can we propose to undeprecate it before the feature freeze?

(Interrupting my holiday slightly to response to this)

Yes you can, and this should be the way forward if needed.
However, the problems seem to only be with __wakeup()​ rather than __sleep()​ so in any case I don't think a counterproposal should undeprecate the latter.
Especially as Tim pointed out on the PR that it is basically impossible to properly implement __sleep()​ if inheritance is involved. [A]​

In any case, going from the analysis from Theodore, and me asking Damien to run an analysis and having a quick skim through them, the main "offenders" are Symfony transient dependencies.
Thus, I'm not even sure a proposal to undeprecate it is warranted, as from what I've seen, many implementations as throwing, do validation on the resulting object, or unset() properties.
And unless I'm misunderstanding, the concerns raised by Nicolas are things that need to be dealt with by frameworks, and possibly some libraries, rather than end-user code.
(And on top of that, it doesn't look like Wordpress would have a hard time at all to support both __unserialize()​ and __wakeup()​.)

I don't mind splitting the PR into 2 different ones, one for __sleep()​ and the other one for __wakeup()​, but once again people are complaining that a 2/3 threshold is seemingly not enough when it is not necessarily an easy threshold to pass.

Best regards,
Gina P. Banyard

[A] Zend: Deprecate __sleep() and __wakeup() by Girgias · Pull Request #19435 · php/php-src · GitHub

Hi,

On Sun, Aug 24, 2025 at 12:58 PM Gina P. Banyard internals@gpb.moe wrote:

I don’t mind splitting the PR into 2 different ones, one for __sleep() and the other one for __wakeup(), but once again people are complaining that a 2/3 threshold is seemingly not enough when it is not necessarily an easy threshold to pass.

The complaint wasn’t that the 2/3 threshold is not enough. It was that the RFC missed some important points and was in that sense misleading. The result was just narrowly passing the threshold. So the point was that it’s quite likely it wouldn’t pass it if the RFC description was correct.

Regards

Jakub