在PHP 2中,相同的对象在序列化后具有2个不同的散列键

时间:2014-02-02 18:12:46

标签: php serialization

采用以下PHP代码:

$a = new stdClass;
$b = $a;
var_dump(spl_object_hash($a) === spl_object_hash($b)); // true

list ($cachedA, $cachedB) = unserialize(serialize([$a, $b]));
var_dump(spl_object_hash($cachedA) === spl_object_hash($cachedB)); // true

$cachedA = unserialize(serialize($a));
$cachedB = unserialize(serialize($b));
var_dump(spl_object_hash($cachedA) === spl_object_hash($cachedB)); // false

似乎对象$ a和对象$ b,即使它们在序列化后是同一个对象,然后反序列化也有不同的哈希标识符。

有人可以解释这种预期的行为吗?

2 个答案:

答案 0 :(得分:2)

如果您回显列表:

echo serialize([$a, $b]);

您正在获取数组,对象($ a)以及返回对象的引用($ b):

a:2:{i:0;O:8:"stdClass":0:{}i:1;r:2;}

这就是为什么它是真的。

我的猜测是两个不同的serialize / unserialize函数调用正在内存中创建两个不同的对象。

spl_object_hash

PHP的序列化格式

答案 1 :(得分:2)

这是完全可以预料的,事实上,serilizing / unserializing在很长一段时间内一直是一个廉价的克隆技巧。

spl_object_hash实际上是PHP中对象的内存分配表中的一个地址。如果您认为散列不是其类型和属性值的结果,则更容易理解为什么具有相同属性的对象被分配了新散列。如果是,则哈希将不断变化。此外,如果你认为它是一个内存地址,那么你会意识到它首先需要在构造对象之前创建,因此,反序列化它会得到一个不同的。

从实施的角度来看,您可以想象为什么分配相同的地址是麻烦和危险的。第一个问题是内存地址或对象散列需要存储在序列化字符串中,内存地址在请求之间发生变化,因此跟踪它并非易事。此外,任何恶意用户都可以更改此哈希并指向地址空间中的任何位置,从而导致致命错误的分段错误。