将 PHP 对象序列化为 JSON [英] Serializing PHP object to JSON

查看:38
本文介绍了将 PHP 对象序列化为 JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以当我偶然发现新的 JsonSerializable 接口.不过它只有 PHP >= 5.4,而且我在 5.3.x 环境中运行.

So I was wandering around php.net for information about serializing PHP objects to JSON, when I stumbled across the new JsonSerializable Interface. It's only PHP >= 5.4 though, and I'm running in a 5.3.x environment.

这种功能是如何实现的PHP <5.4?

How is this sort of functionality achieved PHP < 5.4?

我还没有对 JSON 做过多少工作,但我正在尝试支持应用程序中的 API 层,并将数据对象(否则将被发送到视图)到JSON 将是完美的.

I've not worked much with JSON yet, but I'm trying to support an API layer in an application, and dumping the data object (that would otherwise be sent to the view) into JSON would be perfect.

如果我尝试直接序列化对象,它会返回一个空的 JSON 字符串;这是因为我假设 json_encode() 不知道如何处理这个对象.我应该递归地将对象减少到一个数组中,然后对 那个 进行编码吗?

If I attempt to serialize the object directly, it returns an empty JSON string; which is because I assume json_encode() doesn't know what the heck to do with the object. Should I recursively reduce the object into an array, and then encode that?

$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';

echo json_encode($data) 产生一个空对象:

echo json_encode($data) produces an empty object:

{}

var_dump($data) 但是,按预期工作:

var_dump($data) however, works as expected:

object(Mf_Data)#1 (5) {
  ["_values":"Mf_Data":private]=>
  array(0) {
  }
  ["_children":"Mf_Data":private]=>
  array(1) {
    [0]=>
    array(1) {
      ["foo"]=>
      object(Mf_Data)#2 (5) {
        ["_values":"Mf_Data":private]=>
        array(0) {
        }
        ["_children":"Mf_Data":private]=>
        array(1) {
          [0]=>
          array(1) {
            ["bar"]=>
            object(Mf_Data)#3 (5) {
              ["_values":"Mf_Data":private]=>
              array(1) {
                [0]=>
                array(1) {
                  ["hello"]=>
                  string(5) "world"
                }
              }
              ["_children":"Mf_Data":private]=>
              array(0) {
              }
              ["_parent":"Mf_Data":private]=>
              *RECURSION*
              ["_key":"Mf_Data":private]=>
              string(3) "bar"
              ["_index":"Mf_Data":private]=>
              int(0)
            }
          }
        }
        ["_parent":"Mf_Data":private]=>
        *RECURSION*
        ["_key":"Mf_Data":private]=>
        string(3) "foo"
        ["_index":"Mf_Data":private]=>
        int(0)
      }
    }
  }
  ["_parent":"Mf_Data":private]=>
  NULL
  ["_key":"Mf_Data":private]=>
  NULL
  ["_index":"Mf_Data":private]=>
  int(0)
}

<小时>

附录

1)

所以这是我为 Mf_Data 类设计的 toArray() 函数:

public function toArray()
{
    $array = (array) $this;
    array_walk_recursive($array, function (&$property) {
        if ($property instanceof Mf_Data) {
            $property = $property->toArray();
        }
    });
    return $array;
}

然而,由于 Mf_Data 对象也有对其父(包含)对象的引用,这会因递归而失败.但是当我删除 _parent 引用时,它就像一个魅力.

However since the Mf_Data objects also have a reference to their parent (containing) object, this fails with recursion. Works like a charm though when I remove the _parent reference.

接下来,我使用的转换复杂树节点对象的最终函数是:

Just to follow up, the final function to transform a complex tree-node object I went with was:

// class name - Mf_Data
// exlcuded properties - $_parent, $_index
public function toArray()
{
    $array = get_object_vars($this);
    unset($array['_parent'], $array['_index']);
    array_walk_recursive($array, function (&$property) {
        if (is_object($property) && method_exists($property, 'toArray')) {
            $property = $property->toArray();
        }
    });
    return $array;
}

3)

我再次跟进,对实现进行了一些清理.使用接口进行 instanceof 检查似乎比 method_exists() 更简洁(但是 method_exists() 进行交叉继承/实现).

3)

I'm following up again, with a bit cleaner of an implementation. Using interfaces for an instanceof check seems much cleaner than method_exists() (however method_exists() does cross-cut inheritance/implementation).

使用unset()似乎也有点乱,看来逻辑应该重构为另一种方法.然而,这个实现确实复制了属性数组(由于array_diff_key),所以需要考虑.

Using unset() seemed a bit messy too, and it seems that logic should be refactored into another method. However, this implementation does copy the property array (due to array_diff_key), so something to consider.

interface ToMapInterface
{

    function toMap();

    function getToMapProperties();

}

class Node implements ToMapInterface
{

    private $index;
    private $parent;
    private $values = array();

    public function toMap()
    {
        $array = $this->getToMapProperties();
        array_walk_recursive($array, function (&$value) {
            if ($value instanceof ToMapInterface) {
                $value = $value->toMap();
            }
        });
        return $array;
    }

    public function getToMapProperties()
    {
        return array_diff_key(get_object_vars($this), array_flip(array(
            'index', 'parent'
        )));
    }

}

推荐答案


编辑:目前是 2016 年 9 月 24 日,PHP 5.4 已于 2012 年 3 月 1 日发布,支持已于 2015 年 9 月 1 日结束.不过,这个答案似乎获得了赞成票.如果您仍在使用 PHP <5.4、你正在创造安全风险并危及你的项目.如果您没有令人信服的理由保持 <5.4,或者甚至已经使用版本 >= 5.4,不要使用这个答案,而只使用 PHP>= 5.4(或者,你知道,最近的一) 并实现JsonSerializable 接口


edit: it's currently 2016-09-24, and PHP 5.4 has been released 2012-03-01, and support has ended 2015-09-01. Still, this answer seems to gain upvotes. If you're still using PHP < 5.4, your are creating a security risk and endagering your project. If you have no compelling reasons to stay at <5.4, or even already use version >= 5.4, do not use this answer, and just use PHP>= 5.4 (or, you know, a recent one) and implement the JsonSerializable interface

您将定义一个函数,例如名为 getJsonData();,它将返回一个数组、stdClass 对象或其他一些具有可见参数的对象,而不是返回私有/受保护的,并执行 json_encode($data->getJsonData());.本质上是实现5.4的功能,只是手动调用.

You would define a function, for instance named getJsonData();, which would return either an array, stdClass object, or some other object with visible parameters rather then private/protected ones, and do a json_encode($data->getJsonData());. In essence, implement the function from 5.4, but call it by hand.

这样的事情会起作用,因为 get_object_vars() 从类内部调用,可以访问私有/受保护的变量:

Something like this would work, as get_object_vars() is called from inside the class, having access to private/protected variables:

function getJsonData(){
    $var = get_object_vars($this);
    foreach ($var as &$value) {
        if (is_object($value) && method_exists($value,'getJsonData')) {
            $value = $value->getJsonData();
        }
    }
    return $var;
}

这篇关于将 PHP 对象序列化为 JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆