我想将一个完整的PHP对象图序列化为JSON字符串表示形式,并将其反序列化为相同的PHP对象图。
以下是我考虑的选项摘要,以及它们不适合我的原因:
serialize()
没有做我想要的,因为它使用特定于PHP的格式。我想要一种大多数语言广泛支持的格式,以及人类可读/可编辑的格式。
json_encode()
没有做我想要的,因为它只做简单的值和数组,而不是对象。 (我实际上在实现中使用了这个,见下文。)
var_export()
不处理循环引用,并且不执行我想要的操作(参见上文。)(请注意,我当前的实现也不处理循环引用 - 请参阅注释和以下回复澄清此问题。)
Sebastian Bergmann的Object Freezer是一个很好的实现,但它不能做我想要的 - 它使用非常长的形式,并依赖于使用GUID填充序列化对象。
< / LI> Serialized没有做我想要的事情 - 它实际上不执行序列化,它解析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
}
此方法旨在用于纯树结构聚合 - 不允许循环引用,也不允许对同一对象进行多次引用。换句话说,这不是通用的,例如, serialize()
和unserialize()
,适用于任何PHP对象图。
在我的initial approach中,我使用了一个基本上是基础0对象列表的序列化表单。列表中的第一个对象(编号0)是序列化对象图的根,任何其他对象按其找到的顺序存储。
在当前实现中,JSON表示类似于可能的扩展的原始树结构,使得实际使用JavaScript中的对象图的JSON表示成为可能。唯一的偏差是魔术#type
属性(前缀为#以防止与属性名称冲突)和#hash
“类型”,用于区分array
- 类型哈希(存储为JSON)来自常规array
- 类型数组(存储为JSON数组)。
我出于历史目的将这些关于以前版本的说明留在这里。
简单地通过从不将嵌套对象存储在每个对象的序列化表示内来处理循环引用 - 相反,任何对象引用都存储为具有对象索引的JSON对象 - 例如, {"__oref":2}
是对象列表中索引为2
的对象的引用。
我的实现中的数组引用有问题 - 当我在代码中的var_dump()恢复对数组的对象的引用时,它们被填充,但是在某些时候数组被复制了,而你最终得到空副本。我已经尝试在代码中的任何地方放置&
字符,但无论我通过引用传递的位置,最终结果都是一个空数组。
答案 0 :(得分:2)
完成的脚本(上面发布)符合我的确切要求:
序列化和反序列化整个聚合。
拥有与原始数据结构非常相似的JSON表示。
不要使用动态生成的密钥或其他数据污染数据结构。
它不处理循环引用。正如在comment above中指出的那样,没有正确的方法来存储循环引用或对同一对象的多个引用,因为它们都是相同的。意识到这一点,我认为我的对象图必须是常规树,并接受这个限制为“好事”。
更新:现在可以使用缩进,换行符和空格格式化输出 - 对我来说,为我的目的提供人类可读(和源代码控制友好)表示非常重要。 (可以根据需要启用或禁用格式化。)
答案 1 :(得分:0)
我不知道这是不是你所追求的,但如果你只想获得一个对象的公共属性,get_object_vars($ obj)就可以了。
<?php
class foo {
public $fname = "John";
public $sname = "Doe";
private $status = null;
static $type = "person";
}
$obj = new foo;
print_r( (get_object_vars($obj)) );
print json_encode(get_object_vars($obj));
?>
将输出:
数组([fname] =&gt; John [sname] =&gt; Doe)
{其中 “fname”: “约翰”, “SNAME”: “Doe的”}
上面的方法对于访问函数引用和私有变量没用,但是你可以将它与更多的代码一起使用来打破你想要的东西。
的Dinesh。