我想将完整的 PHP 对象图序列化为 JSON 字符串表示,然后将其反序列化回相同的 PHP 对象图。
以下是我考虑过的选项的摘要,以及它们对我不起作用的原因:
serialize()
没有做我想做的事,因为它使用特定于 PHP 的格式。我想要一种被大多数语言广泛支持并且人类可读/可编辑的格式。json_encode()
没有做我想要的,因为它只做简单的值和数组,而不是对象。(我实际上在我的实现中使用它,见下文。)var_export()
不处理循环引用,也不做我想做的事(见上文。)(请注意,我当前的实现也不处理循环引用 - 请参阅下面的评论和回复以澄清此问题。)Sebastian Bergmann 的Object Freezer是一个很好的实现,但它也没有达到我想要的效果 - 它使用很长的形式,并且依赖于使用 GUID 填充序列化对象。
序列化并没有做我想要的——它实际上并不执行序列化,它解析输出
serialize()
并产生不同的表示,例如 XML,但无法解析该表示。(它也不支持 JSON - XML 格式很长,不是我想要的。)
我现在有一个可行的实现来分享:
https://github.com/mindplay-dk/jsonfreeze
对象图的 JSON 表示形式如下所示:
{
"#type": "Order",
"orderNo": 123,
"lines": [{
"#type": "OrderLine",
"item": "milk \"fuzz\"",
"amount": 3,
"options": null
}, {
"#type": "OrderLine",
"item": "cookies",
"amount": 7,
"options": {
"#type": "#hash",
"flavor": "chocolate",
"weight": "1\/2 lb"
}
}],
"paid": true
}
这种方法设计用于纯树结构聚合 - 不允许循环引用,也不允许对同一对象的多个引用。换句话说,这不是通用的,如 egserialize()
和unserialize()
任何 PHP 对象图的函数。
在我最初的方法中,我使用了一个序列化的表单,它本质上是一个以 0 为基础的对象列表。列表中的第一个对象(编号 0)是序列化对象图的根,任何其他对象都按照它们被发现的顺序存储。
在当前的实现中,JSON 表示类似于原始的树结构,以扩展这是可能的,这使得在 JavaScript 中实际使用对象图的 JSON 表示成为可能。唯一的偏差是魔术#type
属性(以 # 为前缀以防止与属性名称冲突)和#hash
“类型”,用于区分array
-type 哈希(存储为 JSON 对象)和常规array
-type 数组(存储为 JSON 数组)。
出于历史目的,我将在此处留下有关先前版本的这些注释。
循环引用通过从不将嵌套对象存储在每个对象的序列化表示中来简单地处理 - 相反,任何对象引用都存储为具有对象索引的 JSON 对象 - 例如{"__oref":2}
,是对对象中具有索引2
的对象的引用 -列表。
我在我的实现中遇到了数组引用的问题 - 当我在将对象的引用恢复到数组的代码中使用 var_dump() 时,它们正在被填充,但在某些时候数组被复制了,你最终得到空副本。我尝试&
在代码中的任何地方放置字符,但无论我通过引用传递到哪里,最终结果都是一个空数组。