PHP5-序列化对象并存储它们的关系

PHP5-序列化对象并存储它们的关系,php,caching,serialization,Php,Caching,Serialization,我正在编写一个相当复杂的PHP应用程序,其中单个用户操作可以触发许多其他子系统中的更改,我正在考虑使用观察者模式。但是,我想知道是否必须重新创建所有涉及的对象 在序列化对象以存储它们的关系时,是否可以删除它们?比如说 $equipmentHandler = new EquipmentHandler(); $character = new Character(); $character->subscribeOnEquipmentChanged($equipmentHandler); $_S

我正在编写一个相当复杂的PHP应用程序,其中单个用户操作可以触发许多其他子系统中的更改,我正在考虑使用观察者模式。但是,我想知道是否必须重新创建所有涉及的对象

在序列化对象以存储它们的关系时,是否可以删除它们?比如说

$equipmentHandler = new EquipmentHandler();
$character = new Character();
$character->subscribeOnEquipmentChanged($equipmentHandler);

$_SESSION['character'] = serialize($character);
$_SESSION['subscriber'] = serialize($equipmentHandler);
解除银根化后,这种关系会得到保留吗?还是我必须把它们都放在一个物体里

$cache['character'] = $character;
$cache['subscriber'] = $equipmentHandler;
$_SESSION['cache'] = serialize($cache);
如有任何建议,将不胜感激


(注:字符数据需要许多DB请求才能创建,我正在考虑通过写缓存和DB来存储它,但只从缓存策略中读取,因此它无论如何都会被序列化)

根据序列化函数的手册:

要序列化的值。serialize()处理除资源类型之外的所有类型。甚至可以序列化包含自身引用的()数组。正在序列化的数组/对象中的循环引用也将被存储。任何其他引用都将丢失

序列化对象时,PHP将尝试在序列化之前调用成员函数_sleep。这是为了允许对象在序列化之前在最后一分钟进行任何清理等。同样,当使用unserialize()还原对象时,将调用u wakeup member函数


因此,我想这是不可能的,除非你在“睡眠和醒来”中做些聪明的事情,否则关系将保持,但它将不同于你的预期。当序列化两个引用同一个EquipmentHandler的Character实例时,将得到该EquipmentHandler的两个单独实例,而不是预期的单个实例。如本例所示:

<?php

echo "BEFORE SERIALIZE:\n";
class A { }
class B { }

$a = new A;
$b = new B;
$a -> b = $b;

$a2 = new A;
$a2 -> b = $b;

var_dump($a->b);
var_dump($a2->b);

echo "AFTER SERIALIZE:\n";
$a3 = unserialize(serialize($a));
$a4 = unserialize(serialize($a2));

var_dump($a3->b);
var_dump($a4->b);
在磅后面找数字。这是指PHP中的对象ID。在序列化$a->b和$a2->b之前,请引用对象ID为#2:相同实例的对象。但是在序列化之后,它们引用对象ID#5和#7:不同的实例

这对你来说可能是个问题,也可能不是

要恢复到一个B对象的连接,您将需要一些技巧。您可以使用A中的_sleep()处理程序将对B实例的实际引用展平为对B的提及:“我有一个对B的引用”。然后使用a中提到的B实例实现_wakeup()处理程序,以获取新B对象的单个实例


顺便说一句,PHP会话扩展已经自动进行序列化,您无需自己对其进行预序列化:)

您的问题实际上已经解决了!更复杂的情况可能需要使用
\u睡眠
\u唤醒
。。。但考虑到您提供的信息,您所要做的就是——正如您所建议的——“将它们全部集中到一个对象中”

解释 我在信中说:

序列化将维护“相对”引用。(从技术上讲,PHP中没有相对引用,但它是概念化的好方法。)

如果在数组中收集引用和引用变量,序列化数组将保存引用关系。它不会维护原始引用,但会在
取消序列化
返回的新数组的上下文中自动重新创建它。。。对于对象中的内部引用,其工作方式相同

例子 然后,如果您执行
var\u dump($a);变量转储($b->a)$a
$b->a
的对象ID都是“3”,表示它们都引用了
a
的相同实例

object(A)#3 (0) {
}
object(A)#3 (0) {
}

明确指定通过addSubscriber()函数传递引用会删除实例的重复吗?恐怕不会。序列化格式不能以这种方式定义对象。对象在PHP5中通过引用传递。是的,只要您处理PHP代码,它们就是。一旦你序列化/反序列化了对象,你就会处理新的实例,如上图所示。@MathieuK你的回答帮助我发现了PHP中序列化的一个很好的小功能,我认为这一点也不需要太复杂。我很想知道你的想法。
// example objects
class A {}
class B {}
$a    = new A();
$b    = new B();
$b->a = $a;
// collect referenced and referencing objects in array
$cache = array( 'a' => $a, 'b' => $b );
// flatten and recreate cache (represents data stored & retrieved from db)
$cached = unserialize( serialize( $cache ) );
// overwrite local variables from cache
extract( $cached, EXTR_OVERWRITE );
object(A)#3 (0) {
}
object(A)#3 (0) {
}