Bug #76606 [Com]: Widespread regression with Serializable interface and legacy __wakeup method

From: Date: Tue, 10 Jul 2018 15:09:22 +0000
Subject: Bug #76606 [Com]: Widespread regression with Serializable interface and legacy __wakeup method
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-216264@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=76606&edit=1

 ID:                 76606
 Comment by:         westie at typefish dot co dot uk
 Reported by:        westie at typefish dot co dot uk
 Summary:            Widespread regression with Serializable interface
                     and legacy __wakeup method
 Status:             Open
 Type:               Bug
 Package:            Class/Object related
 Operating System:   All tested
 PHP Version:        Irrelevant
 Block user comment: N
 Private report:     N

 New Comment:

https://3v4l.org/rWFHv

To re-iterate, failing on all normal PHP versions yet working as expected on a third party PHP
implementation (HHVM)


Previous Comments:
------------------------------------------------------------------------
[2018-07-10 14:28:37] westie at typefish dot co dot uk

Please reverse the 'expected' and 'actual' results, I swapped them around.

To confirm what the expect result should be:

string(48) "(input)  O:15:"Test_TestClassA":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(48) "(input)  O:15:"Test_TestClassB":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(49) "(input)  O:16:"Test_TestClassAA":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(49) "(input)  O:16:"Test_TestClassBB":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"

------------------------------------------------------------------------
[2018-07-10 14:26:34] westie at typefish dot co dot uk

Description:
------------
According to the documentation, developers are allowed to intermingle the legacy method of
unserialising an object (using __wakeup) AND using the much more modern and cleaner way, using
methods provided in the Serializable interface.

> Note, that when an old instance of a class that implements this interface
> now, which had been serialized before the class implemeted the interface,
> is unserialized, __wakeup() is called instead of the unserialize method,
> which might be useful for migration purposes.
> ~ http://uk1.php.net/manual/en/class.serializable.php

I appear to have found an interesting regression, where this is no longer the case.

Multiple versions affected (possibly including EOL in this list):

- 5.4.29 (EOL?)
- 5.5.13 (EOL?)
- 5.6.0 - 5.6.30
- 5.6.36 specifically
- 7.0.0 - 7.3.0alpha1 (will literally presume ALL of PHP7)

I was planning to implement this functionality in a new project but yeah, I cannot anymore!

Test script:
---------------
<?php

# author note: please review the code on https://3v4l.org/XRr5t
to see
# the full extent of this regression


# base class
class Test_TestClassBase
{
	public $x = 4;
	
	public function __wakeup()
	{
		var_dump("__wakeup");
	}
	
	public function __sleep()
	{
		return array_keys(get_object_vars($this));
	}
	
	public function unserialize($input)
	{
		var_dump("unserialize");
	}
	
	public function serialize()
	{
		var_dump("serialize");
		
		return serialize(get_object_vars($this));
	}
}


# derived classes
class Test_TestClassA extends Test_TestClassBase {}
class Test_TestClassB extends Test_TestClassBase implements Serializable {}
class Test_TestClassAA extends Test_TestClassA implements Serializable {}
class Test_TestClassBB extends Test_TestClassB {}


# run our serialisation
foreach(array("Test_TestClassA", "Test_TestClassB",
"Test_TestClassAA", "Test_TestClassBB") as $class)
{
	$serialised =
'O:'.strlen($class).':"'.$class.'":1:{s:1:"x";i:4;}';
	
	var_dump("(input)  ".$serialised);
	var_dump("(output) ".(unserialize($serialised) instanceof $class ? "true
(passing)" : "false (failing)"));
}

Expected result:
----------------
string(48) "(input)  O:15:"Test_TestClassA":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(48) "(input)  O:15:"Test_TestClassB":1:{s:1:"x";i:4;}"

Warning: Erroneous data format for unserializing 'Test_TestClassB' in /in/XRr5t on line 48

Notice: unserialize(): Error at offset 26 of 39 bytes in /in/XRr5t on line 48
string(24) "(output) false (failing)"
string(49) "(input)  O:16:"Test_TestClassAA":1:{s:1:"x";i:4;}"

Warning: Erroneous data format for unserializing 'Test_TestClassAA' in /in/XRr5t on line
48

Notice: unserialize(): Error at offset 27 of 40 bytes in /in/XRr5t on line 48
string(24) "(output) false (failing)"
string(49) "(input)  O:16:"Test_TestClassBB":1:{s:1:"x";i:4;}"

Warning: Erroneous data format for unserializing 'Test_TestClassBB' in /in/XRr5t on line
48

Notice: unserialize(): Error at offset 27 of 40 bytes in /in/XRr5t on line 48
string(24) "(output) false (failing)"

Actual result:
--------------
string(48) "(input)  O:15:"Test_TestClassA":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(48) "(input)  O:15:"Test_TestClassB":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(49) "(input)  O:16:"Test_TestClassAA":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"
string(49) "(input)  O:16:"Test_TestClassBB":1:{s:1:"x";i:4;}"
string(8) "__wakeup"
string(23) "(output) true (passing)"


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



--
Edit this bug report at https://bugs.php.net/bug.php?id=76606&edit=1


Thread (3 messages)

« previous php.bugs (#216264) next »