我正在编写一个相当复杂的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);
任何建议都将受到赞赏。
(PS。字符数据需要创建很多数据库请求,我正在考虑通过写入缓存和数据库来存储它,但只能从缓存策略中读取,因此它将被序列化)
答案 0 :(得分:4)
将保留一种关系,但它会与您预期的不同。当您序列化两个都引用同一个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);
这个输出是:
BEFORE SERIALIZE:
object(B)#2 (0) {
}
object(B)#2 (0) {
}
AFTER SERIALIZE:
object(B)#5 (0) {
}
object(B)#7 (0) {
}
寻找英镑之后的数字。这是指PHP中的对象ID。在序列化$ a-&gt; b和$ a2-&gt; b之前,请引用具有对象ID#2的对象:相同的实例。但在序列化之后,它们引用了对象ID#5和#7:不同的实例。
这可能会或可能不会成为您的问题。
要恢复与单个B对象的连接,您将不得不变得有点棘手。您可以使用A中的__sleep()处理程序将对B的INSTANCE的实际引用展平为仅提及B:“我有对B的引用”。然后使用A中的B实例提取__wakeup()处理程序来获取新B对象的单个实例。
顺便说一句。 PHP会话扩展已经自动进行序列化,您无需自行预先序列化:)
答案 1 :(得分:0)
根据序列化功能的手册:
要序列化的值。 serialize()处理除resource-type之外的所有类型。您甚至可以序列化()包含对自身的引用的数组。您正在序列化的数组/对象内的循环引用也将被存储。任何其他参考将丢失。
在序列化对象时,PHP将尝试在序列化之前调用成员函数__sleep。这是为了允许对象在序列化之前进行最后一分钟的清理等。同样,当使用unserialize()恢复对象时,将调用__wakeup成员函数。
所以我想除非你在_sleep和_wakeup中做一些聪明的事情,否则这是不可能的
答案 2 :(得分:0)
你的问题实际上有解决方案!更复杂的情况可能需要使用__sleep
和__wakeup
...但是根据您提供的信息,您所要做的就是 - 按照您的建议 - “将它们全部集中到一个对象中”
在an answer to a similar question中,我说:
序列化将保持“相对”引用。 (从技术上讲,在PHP中没有相对引用这样的东西,但它是一种概念化它的好方法。)
如果在数组中收集引用和引用变量,序列化数组将保存引用关系。它不会保留原始引用,但会在
unserialize
返回的新数组的上下文中自动重新创建它。 ...对于对象中的内部引用,它的工作方式相同。
// 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 );
然后,如果你var_dump( $a ); var_dump( $b->a );
,请在下面的输出中注意$a
和$b->a
的对象ID都是'3',表示它们都引用同一个实例A
。
object(A)#3 (0) {
}
object(A)#3 (0) {
}