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


Serialize/unserialize PHP object-graph to JSON

我想将一个完整的PHP对象图序列化为JSON字符串表示,并将其反序列化回相同的PHP对象图。

以下是我考虑过的选项的摘要,以及它们不适合我的原因:

  • serialize()没有做我想做的事,因为它使用特定于PHP的格式。我想要一种被大多数语言广泛支持的格式,并且人类可读/可编辑。

  • json_encode()没有做我想做的事,因为它只做简单的值和数组,而不是对象。(我实际上在我的实现中使用它,见下文。

  • var_export()不处理循环引用,也不做我想做的事(见上文(。 (请注意,我当前的实现也不处理循环引用 - 请参阅下面的评论和回复以澄清此问题。

  • Sebastian Bergmann 的对象冻结器是一个很好的实现,但它也没有做我想要的 - 它使用非常长的形式,并且依赖于使用 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
}

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

在我最初的方法中,我使用了一个序列化形式,它本质上是一个 base-0 的对象列表。列表中的第一个对象(数字 0(是序列化对象图的根,任何其他对象都按找到它们的顺序存储。

在当前的实现中,JSON表示类似于

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


出于历史目的,我将这些关于以前版本的注释留在这里。

循环引用只需从不将嵌套对象存储在每个对象的序列化表示中即可处理 - 相反,任何对象引用都存储为带有对象索引的 JSON 对象 - 例如 {"__oref":2}是对对象列表中索引2的对象的引用。

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

完成的脚本(上面发布(符合我的精确要求:

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

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

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

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

更新:输出现在可以用缩进、换行符和空格进行格式化 - 对我来说,为我的目的提供一个人类可读(和源代码控制友好(的表示形式很重要。(可以根据需要启用或禁用格式设置。

我不知道

这是否是你所追求的,但如果你只对获取对象的公共属性感兴趣,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] => John [sname] => Doe (

{"fname":"John","sname":"Doe"}

上面的方法对于访问函数引用和私有变量是无用的,但你可以将其与更多的代码结合使用,以敲出你想要的东西。

迪内什。