php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #26765 Objects destroyed twice?
Submitted: 2004-01-02 07:15 UTC Modified: 2004-05-26 17:45 UTC
Votes:14
Avg. Score:4.5 ± 1.2
Reproduced:9 of 11 (81.8%)
Same Version:5 (55.6%)
Same OS:5 (55.6%)
From: alex_mailbox53 at yahoo dot com Assigned: andi (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5CVS-2004-03-15 OS: *
Private report: No CVE-ID: None
 [2004-01-02 07:15 UTC] alex_mailbox53 at yahoo dot com
Description:
------------
The following code displays only one serialized object, but 
should display two: 
class SFTemplate { 
    public $content; 
    public $parent; 
    function __construct() { $this->content = new 
SFTemplateContent($this); } 
} 
class SFTemplateContent { 
    protected $template; 
    protected $items  = array(); 
    function __construct($tpl) { $this->template = $tpl; } 
    function add($item) { 
        $this->items[] = $item; 
        $item->parent = $this->template; 
    } 
} 
$t = new SFTemplate(); 
$t->content->add(new SFTemplate()); 
print_r(unserialize(serialize($t))); 
print '<hr>'; 
$t->content->add(new SFTemplate()); 
print_r(unserialize(serialize($t))); 
 
Adding more objects to SFTemplateContent object prevents 
object from deserialization. With 1 object in items array it works 
ok. 
 

Expected result:
----------------
two dumps of deserialized objects 

Actual result:
--------------
one dump 
 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-01-11 10:46 UTC] sniper@php.net
I played around and tested what happens with PHP 4..this has nothing to do with serialization, following works fine
in PHP 4, in PHP 5 it causes several memleaks and the resulting object is not quite correct:

<?php

class SFTemplate { 
    var $content; 
    var $parent; 

    function SFTemplate() {
        $this->content = new SFTemplateContent($this);
    } 
} 

class SFTemplateContent { 
    var $template; 
    var $items  = array(); 

    function SFTemplateContent($tpl) {
        $this->template = $tpl;
    } 

    function add($item) { 
        $this->items[] = $item; 
        $item->parent = $this->template; 
    } 
} 

$t = new SFTemplate(); 

$t->content->add(new SFTemplate()); 

var_dump($t);

?>

 [2004-02-04 20:42 UTC] sniper@php.net
Latest CVS checkout of HEAD today doesn't show any leaks anymore, but the output is still incorrect. (or it's incorrect with PHP 4, who knows :).

And changing that var_dump() -> print_r() causes segfault..

 [2004-02-08 21:43 UTC] moriyoshi@php.net
The leaks are caused by circular references. So the only 
remaining issue is the segfault bug. 

Perhaps related to bug #25975

 [2004-02-08 22:06 UTC] moriyoshi@php.net
And several more notes follow.

- It seems circular references are now properly handled 
with the new destructor code recently brought into the 
engine by Zeev.

- As you know, in php5 objects are assigned to variables 
by reference, so it'd be a fair comparison if the 
script goes like this:


<?php
class foo {
    var $bar = false;
    var $parent = false;

    function foo() {
        $this->bar = &new bar($this);
    }
    function __destruct() {
        echo "object ".__CLASS__." is being 
destroyed.\n";
    }
}

class bar {
    var $foo = false;
    var $items  = array();

    function bar(&$foo) {
        $this->foo = &$foo;
    }

    function add(&$item) {
        $this->items[] = &$item;
        $item->parent = &$this->foo;
    }
    function __destruct() {
        echo "object ".__CLASS__." is being 
destroyed.\n";
    }
}

$t = &new foo();

$t->bar->add(new foo());

var_dump($t);
?>

This yields

object foo is being destroyed.
object bar is being destroyed.
object foo is being destroyed.
object bar is being destroyed.

It looks like these objects have been destroyed twice...

- I wasn't able to reproduce the segfault even though I 
changed var_dump() to print_r().

 [2004-02-29 16:46 UTC] awulf at ev1 dot net
-- quoting moriyoshi@php.net 
$t = &new foo();

$t->bar->add(new foo());

var_dump($t);
?>

This yields

object foo is being destroyed.
object bar is being destroyed.
object foo is being destroyed.
object bar is being destroyed.
-- end quote

this looks like it's doing the right thing to me. first you make a foo, which in its constructor makes a bar. so you have 2 objects. then you add another foo to the first foo's bar, which then creates another bar, so you have 4 objects total. then they all get destroyed. looks good to me, yeah?
 [2004-03-07 17:46 UTC] jaanus at heeringson dot com
Actually, you only create 2 objects in the example above, the initial foo and the bar from foo's constructor. The rest are only references.

I still get the "Segmentation fault (11)", and by debugging my own apps i can only concurr that this is not solved. I also sometimes get some kind of race-condition where the apache process heads up to 99.6%, but this occurs rarely.

How come the "var_dump() to print_r()" matters? I get segfaults without either (on the sample code). The segfaults only occur the second time the code is run on the same process, not when initially loading the page.
 [2004-03-10 11:37 UTC] jaanus at heeringson dot com
Ok, I have found out why the above example occaisionally worked. It seems the order in which properties are declared play a ignificant role. I guess the "destruction" propagates along in the order of declarations. You can try it yourself by swaping two lines in the code below (the lines are commented).

<pre>
<?php
class factory {
	public $child;

	public function make($class,$parent=null) {
		$_temp=new $class($this);
		$this->child[$class][]=$_temp;
		if(is_object($parent)) {
			$parent->mount($_temp);
		}
		Return $_temp;
	}
}

class root {
	public $child;	//If the order of these two lines
	public $ref;	//is changed, you get a segfault
	public $parent;

	public function __construct($factory){
		$this->ref['factory']=$factory;
	}

	public function mount($obj){
		$this->child[]=$obj;
		$obj->setParent($this);
		$obj->setRef($this->ref+array('root'=>$this));
	}

	public function setRef($pref) {
		$this->ref=array_merge($pref,$this->ref);
	}

	public function setParent($parent){
		$this->parent=$parent;
	}
}

class child extends root{
	public function mount($obj){
		$this->child[]=$obj;
		$obj->setParent($this);
		$obj->setRef($this->ref+array('child'=>$this));
	}
}

$factory=new factory();
$a=$factory->make('root');
$b=$factory->make('child',$a);
$c=$factory->make('child',$a);
print_r($a);
?>
</pre>
 [2004-04-09 11:06 UTC] sniper@php.net
Andi, is this a bug or not? 

 [2004-05-23 22:38 UTC] andi@php.net
Can you please try the latest CVS and see if the crashes persist?
Thanks.

Andi
 [2004-05-26 17:03 UTC] alex_mailbox53 at yahoo dot com
Sorry, I did download the CVS version yet. I tested the issue with PHP5 RC2 and it works Ok - bug is fixed.

Thank you!

Alexander
 [2004-05-26 17:45 UTC] derick@php.net
Let's close it then.
 
PHP Copyright © 2001-2023 The PHP Group
All rights reserved.
Last updated: Tue Feb 07 02:05:48 2023 UTC