在PHP中,两个相同的对象在序列化后有两个不同的哈希键

在PHP中,两个相同的对象在序列化后有两个不同的哈希键,php,serialization,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 $cached

以下面的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即使是序列化后反序列化的同一对象,也有不同的哈希标识符


有人能解释一下这是预期的行为吗?

如果你重复一下列表:

echo serialize([$a, $b]);
您将获得数组、对象($a)和对象($b)的引用:

这就是为什么这是真的

我的猜测是,两个不同的序列化/非序列化函数调用正在内存中创建两个不同的对象

spl\u对象\u散列
PHP的序列化格式

如果您呼出列表:

echo serialize([$a, $b]);
您将获得数组、对象($a)和对象($b)的引用:

这就是为什么这是真的

我的猜测是,两个不同的序列化/非序列化函数调用正在内存中创建两个不同的对象

spl\u对象\u散列
PHP的序列化格式

这完全是意料之中的,事实上,序列化/非序列化是一种廉价的对象克隆技巧已有相当一段时间了

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


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

这完全是意料之中的,事实上,序列化/非序列化在相当长一段时间内一直是一种廉价的对象克隆技巧

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


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

在取消序列化(serialize($b))之后,尝试在对象上使用var_dump,看看是否有任何区别。我不知道这背后的原因/含义,但似乎当你序列化它们时,它们本身就失去了引用。unserialize创建一个包含序列化数据的新对象。只要不使用标识映射之类的东西,它就不是一个实体。尝试在取消序列化(序列化($b))后对对象使用var_dump,看看是否有任何区别。我不知道这背后的原因/含义,但似乎当你序列化它们各自时,它们会丢失引用。unserialize创建一个包含序列化数据的新对象。只要不使用身份映射之类的东西,它就不是一个实体。