将PHP对象图序列化/反序列化为JSON

min*_*.dk 6 php arrays serialization json reference

我想将一个完整的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
}
Run Code Online (Sandbox Code Playgroud)

此方法旨在用于纯树结构聚合 - 不允许循环引用,也不允许对同一对象进行多次引用.换句话说,这不是通用的,例如serialize(),unserialize()任何PHP对象图的功能.

在我最初的方法中,我使用了一个序列化的表单,它基本上是一个基础0对象列表.列表中的第一个对象(编号0)是序列化对象图的根,任何其他对象按其找到的顺序存储.

在当前实现中,JSON表示类似于可能的扩展的原始树结构,使得实际使用JavaScript中的对象图的JSON表示成为可能.唯一的偏差是magic #type属性(前缀为#以防止与属性名冲突)和#hash"type",用于区分array类型哈希(存储为JSON对象)与常规array类型数组(存储为JSON数组).


出于历史目的,我将这些关于以前版本的说明留在这里.

简单地通过从不将嵌套对象存储在每个对象的序列化表示内来处理循环引用 - 相反,任何对象引用都存储为具有对象索引的JSON对象 - 例如,{"__oref":2}是对象中具有索引2的对象的引用- 名单.

我在我的实现中遇到了数组引用的问题 - 当我在代码中的var_dump()恢复对数组的对象的引用时,它们被填充,但在某些时候数组被复制,你最终得到空副本.我已经尝试&在代码中的任何地方放置字符,但无论我通过引用传递的位置,最终结果都是一个空数组.

min*_*.dk 1

完成的脚本(上面发布)满足我的精确要求:

  • 序列化和反序列化整个聚合。

  • 拥有与原始数据结构非常相似的 JSON 表示形式。

  • 不要用动态生成的键或其他数据污染数据结构。

它不处理循环引用。正如上面的评论所指出的,没有正确的方法来存储循环引用或对同一对象的多个引用,因为它们都是相等的。意识到这一点,我决定我的对象图必须是一个常规树,并接受这个限制作为“一件好事”。

更新:输出现在可以使用缩进、换行符和空格进行格式化 - 对于我来说,拥有人类可读(且源代码控制友好)的表示形式对于我的目的来说非常重要。(可以根据需要启用或禁用格式。)