7

我想将完整的 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() 时,它们正在被填充,但在某些时候数组被复制了,你最终得到空副本。我尝试&在代码中的任何地方放置字符,但无论我通过引用传递到哪里,最终结果都是一个空数组。

4

2 回答 2

1

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

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

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

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

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

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

于 2012-06-07T01:42:29.370 回答
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] => John [sname] => Doe)

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

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

迪内什。

于 2012-05-31T15:12:14.697 回答