|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2004-02-20 16:22 UTC] hawcue at yahoo dot com
Description:
------------
Please read the codes first.
The actual output shows two copies of $parentNode are
generated by unserialize(). However, this is not
what I expect because I am using reference and
$newParent->child->parent and $newParent should
refer to the same storage if serialize/unserialize
works correctly.
The problem can be partially solved by using
the following line to do serialize:
$str = serialize(&$parentNode); // an ampersand is used
This will generate a compiling warning (depreciation
of using ampersand in function parameters).
Reproduce code:
---------------
class Node {
var $value;
var $child;
var $parent;
function Node($value) {
$this->value = $value;
}
function setParent(&$parent) {
$this->parent = &$parent;
}
function setChild(&$child) {
$this->child = &$child;
}
}
$parentNode = new Node('parent');
$childNode = new Node('child');
$parentNode->setChild($childNode);
$childNode->setParent($parentNode);
$str = serialize($parentNode);
$newParent = unserialize($str);
$newParent->value = 'new parent';
echo $newParent->child->parent->value;
echo $newParent->value;
Expected result:
----------------
new parent
new parent
Actual result:
--------------
parent
new parent
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 17:00:01 2025 UTC |
<?php // this example is for php 4 class Node { var $value; var $child; var $parent; var $load; var $__destroyed = false; function Node($value) { $this->value = $value; global $load; $this->load = $load; } function setParent(&$parent) { $this->parent = &$parent; } function setChild(&$child) { $this->child = &$child; } /** * @return void * @desc fake __destroy from a php 4 point of view */ function __destroy() { $props = get_object_vars($this); foreach($props as $propName => $propValue) { unset($propValue); if(is_object($this->$propName)) { if(method_exists($this->$propName, '__destroy') AND $this->$propName->__destroyed !== false) { $this->$propName->__destroy(); } } if(isset($this->$propName)) { unset($this->$propName); } } } } header('Content-type: text/plain'); // small load to check the serialized string $loadSize = 4; // big load to check leaking //$loadSize = 32 * 1024; $load = str_repeat('.', $loadSize); for($i = 0;$i<10;$i++) { echo '-------------------- '.(memory_get_usage()/1024).' -------------------------'.chr(10); $serMe = array(); $serMe['parent'] =& new Node('parent'); $serMe['child'] =& new Node('child'); /* * this will work too !! * $serMe['parent'] = new Node('parent'); * $serMe['child'] = new Node('child'); */ $serMe['parent']->setChild($serMe['child']); $serMe['child']->setParent($serMe['parent']); $str = serialize($serMe); /* * 1.Problem: * * You have 2 or more objects with circular references to one another. * Serializing these objects will result in unexpected behaviour when * unserializing them: * * Former references will become copies. * * This is because the php serialize handler can not handle references, * unless all involved objects, variables ... are within an array(), * that will be serialized. * * This should be selfexplaining (just take a look at the length ...): * echo serialize($serMe['parent']); * echo serialize($serMe); * results in: * O:4:"node":5:{s:5:"value";s:6:"parent";s:5:"child";O:4:"node":5:{s:5:"value";s:5:"child";s:5:"child";N;s:6:"parent";O:4:"node":5:{s:5:"value";s:6:"parent";s:5:"child";R:3;s:6:"parent";N;s:4:"load";s:4:"....";s:11:"__destroyed";b:0;}s:4:"load";s:4:"....";s:11:"__destroyed";b:0;}s:6:"parent";N;s:4:"load";s:4:"....";s:11:"__destroyed";b:0;} * a:2:{s:6:"parent";O:4:"node":5:{s:5:"value";s:6:"parent";s:5:"child";O:4:"node":5:{s:5:"value";s:5:"child";s:5:"child";N;s:6:"parent";R:2;s:4:"load";s:4:"....";s:11:"__destroyed";b:0;}s:6:"parent";N;s:4:"load";s:4:"....";s:11:"__destroyed";b:0;}s:5:"child";R:4;} * * PLEASE GIVE THE WORLD PROPER DOCUMENTATION ON THIS (or prove us wrong) * * 2.Problem: * * The loop below will result in extensive leaking (use the big $loadsize ...), * unless you help yourself and unset all the properties manually * see Node::__destroy() * */ $serMe['parent']->__destroy(); $serMe['child']->__destroy(); $serMe = unserialize($str); unset($str); $serMe['parent']->value = 'new parent'; echo '-->'.$serMe['parent']->child->parent->value.chr(10); echo '-->'.$serMe['parent']->value.chr(10); $serMe['parent']->__destroy(); $serMe['child']->__destroy(); unset($serMe); } ?>