#36424 [Asn]: Serializable interface breaks object references

From: Date: Tue, 06 Jun 2006 19:02:38 +0000
Subject: #36424 [Asn]: Serializable interface breaks object references
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-98097@lists.php.net to get a copy of this message
 ID:               36424
 Updated by:       tony2001@php.net
 Reported By:      mastabog at hotmail dot com
 Status:           Assigned
 Bug Type:         SPL related
 Operating System: *
 PHP Version:      5.1.3RC2-dev
 Assigned To:      helly
 New Comment:

Yeah, calling a function in an endless loop usually ends up with stack
overflow. It's expected and has nothing to do with this report.


Previous Comments:
------------------------------------------------------------------------

[2006-06-06 18:51:37] hos dot endre at cafecsoport dot hu

Crashing also reproducable.

Win2000Prof / PHP514

My related problem is that serializing a Serializable object, thats
some object property holds a reference to the serialized root object,
PHP crashes.

The magic function __serialize have too much sideFx for me - making the
object unworkable,
but I cant figure out how nested serialize function calls could work
properly.

Probably when the native serialize function is handles a nested call
then could hook up the root calls pointer map?

And then could this work for nested unserialization?

At this time I have no vision about the sideFx of this mention.

Right now I dont have a prepared C development environment to work out,
and dont remember how the related part of the code workx. As I remember
nested call test was implemented in the __autoload() function.

Since it can cause crashes please take more care on this bug.

Just uncomment 'implements Serializable' to let it crash.

class A // implements Serializable
{
	public $dontSerialize;
	public $that;

	function __construct($that = null)
	{
		$this->that = ($that === null) ? new A($this) : $that;
	}

	function serialize()
	{
		return serialize($this->that);
	}

	function unserialize($serialized)
	{
		$this->that = serialize($serialized);
	}
}

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

[2006-04-11 11:43:11] sniper@php.net

Assigned to the SPL maintainer.

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

[2006-03-18 10:30:38] nohn@php.net

To make this fail, it needs to be

    $this->assertEquals(true, $new_oC->A === $new_oC->B->A);


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

[2006-03-18 10:29:16] nohn@php.net

When playing around with this bug, I discovered this:

While

    var_dump($new_oC->A === $new_oC->B->A);

Results into bool(false)

    $this->assertEquals($new_oC->A, $new_oC->B->A);

Does not fail!

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

[2006-02-17 06:27:22] mastabog at hotmail dot com

Description:
------------
First of all, I know this is very new and undocumented.

The Serializable interface serialize() method breaks reference of
objects that are properties of the serialized object and that they
themselves implement the Serializable interface. See the reproduceable
code below.

an echo over $ser yields:

C:1:"C":85:{a:2:{s:1:"A";C:1:"A":6:{a:0:{}}s:1:"B";C:1:"B":32:{a:1:{s:1:"A";C:1:"A":6:{a:0:{}}}}}}

It's visible that the last A is not a reference but a new class
instance.

I know that Serializable::unserialize() acts as a constructor, but
shouldn't object references be honored by Serializable::serialize() the
same way unserialize() does when the class does not implement the
Serializable interface.

If we remove the Serializable interface from class A and leave it like
this:

class A {}

then $ser looks like the following:

O:1:"C":2:{s:1:"A";O:1:"A":0:{}s:1:"B";O:1:"B":1:{s:1:"A";r:2;}}

And it's visible that the last A is a reference.

If this is all intended behavior for the Serializable interface to
break object references then you can ignore this bug report. I hope
it's not though, because it would have provided a better alternative to
the __sleep() and __wakeup() (e.g. classes extending the PDO class
cannot be serialized using __sleep() and __wakeup(), neither by
overloading nor by default)

Reproduce code:
---------------
class A implements Serializable
{
	public function serialize ()
	{
		$serialized = array();
		foreach($this as $prop => $val) {
			$serialized[$prop] = $val;
		}
		return serialize($serialized);
		
		//return serialize(get_object_vars($this));
	}

	function unserialize($serialized)
	{
		foreach(unserialize($serialized) as $prop => $val) {
			$this->$prop = $val;
		}
		return true;
	}
}

class B extends A
{
	public $A;
}

class C extends A
{
	public $A;
	public $B;
}

$oC = new C();
$oC->A = new A();
$oC->B = new B();
$oC->B->A = $oC->A;

echo $oC->A === $oC->B->A ? "yes" : "no", "\n"; 
$ser = serialize($oC);
$new_oC = unserialize($ser);
echo $new_oC->A === $new_oC->B->A ? "yes" : "no", "\n"; 

Expected result:
----------------
yes
yes


Actual result:
--------------
yes
no



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


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


Thread (25 messages)

« previous php.bugs (#98097) next »