|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[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
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 06:00:02 2025 UTC |
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); ?>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().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>