|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2011-09-27 20:06 UTC] mapi at pdepend dot org
Description: ------------ There is a regression or change in how object structures are serialized or unserialized in PHP's 5.4.x branch. I am sorry that I cannot give a more detailed explanation and say what has changed and causes this issue, but an object cache for one of my applications fails with all PHP 5.4.x version, while it works with all PHP 5.2.x and PHP 5.3.x versions. I would expect that this behavior change would also affect other applications or libraries that utilize PHP's (un)serialize functions. Test script: --------------- #!/bin/sh PHP_BIN=/usr/local/bin/php540 cd /tmp git clone https://github.com/pdepend/pdepend.git cd pdepend "$PHP_BIN" ./src/bin/pdepend.php --summary-xml=sum.xml src/main/ "$PHP_BIN" ./src/bin/pdepend.php --summary-xml=sum.xml src/main/ Expected result: ---------------- PHP_Depend @package_version@ by Manuel Pichler Parsing source files: ............................................................ 60 ............................................................ 120 ............................................................ 180 ................ 196 Executing CyclomaticComplexity-Analyzer: ............................................................ 1200 .............................. 1818 Executing ClassLevel-Analyzer: ............................................................ 1200 ...................... 1647 Executing CodeRank-Analyzer: .......... 217 Executing Coupling-Analyzer: ............................................................ 1200 .......................................... 2048 Executing Hierarchy-Analyzer: ............................................................ 1200 ................................ 1852 Executing Inheritance-Analyzer: ........................... 549 Executing NPathComplexity-Analyzer: ............................................................ 1200 ............................... 1830 Executing NodeCount-Analyzer: ............................................................ 1200 .................. 1564 Executing NodeLoc-Analyzer: ............................................................ 1200 ............................ 1766 Generating pdepend log files, this may take a moment. 00:16; Memory: 124.00Mb Actual result: -------------- PHP_Depend @package_version@ by Manuel Pichler Parsing source files: ............................................................ 60 ............................................................ 120 .................PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 .........................PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 .........PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 ......... 180 ...........PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569 ..... 196 Executing CyclomaticComplexity-Analyzer: ....................PHP Fatal error: Call to a member function findChildrenOfType() on a non-object in /tmp/pdepend/src/main/php/PHP/Depend/Code/AbstractClassOrInterface.php on line 268 Fatal error: Call to a member function findChildrenOfType() on a non-object in /tmp/pdepend/src/main/php/PHP/Depend/Code/AbstractClassOrInterface.php on line 268 Patchesfix-serialize-in-sleep-and-wakeup (last revision 2011-10-13 16:21 UTC by mike@php.net)Pull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 04:00:02 2025 UTC |
What PHP_Depend does is serializing double linked object trees like. It uses __sleep() to reset the child-parent link before a tree gets serialized: class Node { protected $parent; protected $nodes = array(); public function __sleep() { return array('nodes'); } } And it uses __wakeup() to restore this link during the unserialization: class Node { protected $parent; protected $nodes = array(); public function __sleep() { return array('nodes'); } public function __wakeup() { foreach ($this->nodes as $node) { $node->parent = $this; } } } Now it seems that under certain circumstances the $this->nodes property is an array when __wakeup() is called, but instead of objects the array values are NULL. This happens when the following PHP Warning occurs: PHP Warning: Creating default object from empty value in /tmp/pdepend/src/main/php/PHP/Depend/Code/ASTNode.php on line 569Okay, I tried for several hours to create a reproducable outside of PHP_Depend's context, but I cannot reproduce this behavior :( But at least I came up with a small code fragement that illustrates this behavior: <?php class Test { function method() { $this->prop[$y]++; } } which was translated into the following object graph: Statement Expression MemberPrimaryPrefix <---------- Variable | PropertyPostfix | ArrayIndexExpression [Same Instance] Identifier | Variable | PostfixExpression | MemberPrimaryPrefix ---------- Variable PropertyPostfix ArrayIndexExpression Identifier Variable And this second reference to MemberPrimaryPrefix is NULL after unserialization with PHP 5.4 and it is just a second clone with PHP < 5.4OTOH, the following working script suggests that this is not the source of failure: <?php class node { public $parent; public $nodes = array(); public $path; public $temp; function __toString() { return $this->parent ? $this->parent . "/" . $this->path : $this->path; } function __construct(node $parent = null, $path = ".") { $this->parent = $parent; $this->path = $path; if (is_dir($this)) foreach (scandir($this) as $p) { if ($p[0] != ".") { $this->nodes[] = new node($this, $p); } } } function __sleep() { $this->temp = serialize($this->nodes); return array("path", "temp"); } function __wakeup() { $this->nodes = unserialize($this->temp); $this->temp = null; foreach ($this->nodes as $n) { $n->parent = $this; } } } $tree = new node(null, @$_SERVER["argv"][1] ?: "."); $s = serialize($tree); var_dump($s); $temp = unserialize($s); print_r($temp);Ok, now got a reproduce case: <?php class node { protected $parent; protected $nodes = array(); protected $path; protected $temp; function __toString() { return $this->parent ? $this->parent . "/" . $this->path : $this->path; } function __construct(node $parent = null, $path = ".") { $this->parent = $parent; $this->path = $path; if (is_dir($this)) foreach (scandir($this) as $p) { if ($p[0] != ".") { $this->nodes[] = new node($this, $p); } } } function __sleep() { $this->temp = serialize($this->nodes); return array("path", "temp"); } function __wakeup() { $this->nodes = unserialize($this->temp); $this->temp = null; foreach ($this->nodes as $n) { $n->parent = $this; } } function createWeirdConnections() { foreach ($this->nodes as $n) { $a = $this->nodes; shuffle($a); $n->nodes[] = current($a); } } } $tree = new node(null, @$_SERVER["argv"][1] ?: "."); $tree->createWeirdConnections(); $s = serialize($tree); $temp = unserialize($s);