Re: [RFC] [VOTE] Deprecations for PHP 8.5
| From: | Nicolas Grekas | Date: | Wed, 13 Aug 2025 16:36:22 +0000 |
| Subject: | Re: [RFC] [VOTE] Deprecations for PHP 8.5 | ||
| References: | 1 2 3 4 5 6 7 8 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-128467@lists.php.net to get a copy of this message | ||
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);
}