使用依赖项注入序列化对象时的PHP无限递归
两者都实现了一个将对象序列化为XML的接口。但由于交叉引用,它会陷入无限循环。如何解决这个问题?这是我的设计缺陷吗?如何改进使用依赖项注入序列化对象时的PHP无限递归,php,oop,dependency-injection,xml-serialization,Php,Oop,Dependency Injection,Xml Serialization,两者都实现了一个将对象序列化为XML的接口。但由于交叉引用,它会陷入无限循环。如何解决这个问题?这是我的设计缺陷吗?如何改进 我可以想到在序列化之前最后一次清理依赖项的方法。但我不知道这是否是最好的方法。当序列化程序简单地遍历对象图时,当您具有双向关联时,您将不可避免地遇到无限递归,例如,文章具有并属于许多注释。序列化程序将在文章和注释之间来回遍历。与其说是依赖关系,不如说是对象之间的关联和链接方式 我可以想出三种方法来解决这个问题: 目标跟踪 最简单的解决方案可能是教序列化程序记录它已序列化的
我可以想到在序列化之前最后一次清理依赖项的方法。但我不知道这是否是最好的方法。当序列化程序简单地遍历对象图时,当您具有双向关联时,您将不可避免地遇到无限递归,例如,文章具有并属于许多注释。序列化程序将在文章和注释之间来回遍历。与其说是依赖关系,不如说是对象之间的关联和链接方式 我可以想出三种方法来解决这个问题: 目标跟踪 最简单的解决方案可能是教序列化程序记录它已序列化的对象。为此,请在序列化之前运行要序列化的每个对象。将该散列存储在数组中,当散列已经在记录的列表中时,只需跳过它或插入一个idref属性指向已插入元素的元素,例如
class foo
{
private $deps
public function __construct(bar $obj)
{
$this->deps=$obj;
}
}
class Bar
{
private $property; //Instance of Bar which have setter and getter methods
}
元数据映射模式
另一种选择是利用模式的等效物进行序列化:
处理对象关系映射的大部分代码描述了数据库中的字段如何与内存对象中的字段相对应。由此产生的代码往往是乏味和重复的编写。元数据映射允许开发人员以简单的表格形式定义映射,然后由通用代码处理,以执行读取、插入和更新数据的细节
您可以定义哪些属性应该序列化为XML,而不是定义哪些属性与数据库中的哪些列匹配。然后,序列化程序将检查对象的类型,并应用映射中的规则来处理它。显然,地图不应该包含任何可能导致循环引用的属性
映射可以像数组一样简单,然后可以将其传递给序列化程序进行配置。这样,您的对象和序列化程序都不需要知道映射如何发生的任何细节。缺点是,您需要定义映射
接见者模式
还有一种选择是使用,其中序列化程序访问对象图,然后对象有选择地通过双重分派传递要序列化的数据。同样,您必须确保只传递不能导致循环引用的数据。缺点是它需要所有相关的类来接受访问者
我不会详细介绍这个模式,因为它在web上已经被广泛地介绍过了。我不知道为什么您首先要尝试用它的依赖项序列化类。您的类封装了哪些数据?你不能序列化它而不是整个类吗?它是两个类<代码>文章代码>和注释<代码>注释类别依赖于
文章
类别<代码>评论类使用文章类中的一些数据。我有一个XMLSerialize对象,它自动递归地序列化所有对象。当前排除依赖对象的一种方法是取消设置它。你是说序列化依赖对象不好吗?你还没有接受我的答案,所以请你更新你的问题,指出为什么我的答案不能帮助解决你的问题?@Gordon抱歉,我差点忘了。你的回答很有帮助。虽然我最终使用了不同的解决方案。我使用了一个标记接口,该接口用于标记xmlserializeble
对象,并将依赖项对象封装在与目标对象关联的另一个对象中
class Serializer
{
private $record = array();
public function serialize($value)
{
$hash = spl_object_hash($value);
if (isset($this->record[$hash])) {
// skip or insert element with idref to XML
} else {
$this->record[$hash] = true;
// turn $value to XML
}
}
// … more code