如何使用JsonSerializable :: jsonSerialize()忽略null属性?

时间:2016-12-13 15:22:28

标签: php json

假设我们有一个简单的对象来使用嵌套对象进行序列化:

class User implements \JsonSerializable
{

    private $name;
    private $email;
    private $address;

    public function jsonSerialize()
    {
        return [
            'name'  => $this->name,
            'email'  => $this->email,
            'address' => $this->address
        ];
    }
}

嵌套对象:

class Address implements \JsonSerializable
{

    private $city;
    private $state;

    public function jsonSerialize()
    {
        return [
            'city'  => $this->city,
            'state' => $this->state
        ];
    }
}

我们使用json_encode()进行序列化,这将使用原生JsonSerializable::jsonSerialize()

$json = json_encode($user);

如果$name$state为空,请告知如何:

{
    "email": "john.doe@test.com",
    {
        "city": "Paris"
    }
}

而不是:

{
    "name": null,
    "email": "john.doe@test.com",
    {
        "city": "Paris",
        "state": null
    }
}

2 个答案:

答案 0 :(得分:1)

在返回的数组周围包裹array_filter,例如

public function jsonSerialize()
    return array_filter([
        'city'  => $this->city,
        'state' => $this->state
    ]);
}

这将删除任何等于false(松散比较)的条目,其中包括任何空值,但也包括0和false。如果您需要严格,例如只有空值,提供以下回调:

function($val) { return !is_null($val); }

请参阅array_filter的文档:

  

(PHP 4> = 4.0.6,PHP 5,PHP 7)

     

迭代数组中的每个值,将它们传递给回调函数。如果回调函数返回true,则将数组中的当前值返回到结果数组中。数组键被保留。

另一个选择是使用JMX Serializer,这是一个高度可配置的JSON,XML和YAML序列化程序。但它要重得多。有关详细信息,请参阅Exclude null properties in JMS Serializer

答案 1 :(得分:0)

我的评论不正确,array_walk_recursive()可以更改值,但不能取消设置,所以我创建了一个自定义递归函数,只需几行代码:

<?php

$a = (object) array(
  'first' => null,
  'second' => 10,
  'third' => (object) array(
    'second-first' => 100,
    'second-second' => null,
    'second-third' => 300
  ),
  'fourth' => 20,
  'fifth' => null,
  'sixth' => 10);

function remove_null_values($a) {
  $ret = (is_array($a) ? array() : new stdClass());
  foreach ($a as $k => $v) {
    if (is_array($v) || is_object($v)) {
      if (is_object($ret))
        $ret->$k = remove_null_values($v);
      else
        $ret[$k] = remove_null_values($v);
    }
    elseif (!is_null($v)) {
      if (is_object($ret))
        $ret->$k = $v;
      else
        $ret[$k] = $v;
    }
  }
  return $ret;
}

输出:

object(stdClass)#2 (6) {
  ["first"]=>
  NULL
  ["second"]=>
  int(10)
  ["third"]=>
  object(stdClass)#1 (3) {
    ["second-first"]=>
    int(100)
    ["second-second"]=>
    NULL
    ["second-third"]=>
    int(300)
  }
  ["fourth"]=>
  int(20)
  ["fifth"]=>
  NULL
  ["sixth"]=>
  int(10)
}
object(stdClass)#3 (4) {
  ["second"]=>
  int(10)
  ["third"]=>
  object(stdClass)#4 (2) {
    ["second-first"]=>
    int(100)
    ["second-third"]=>
    int(300)
  }
  ["fourth"]=>
  int(20)
  ["sixth"]=>
  int(10)
}

编辑:我更新了代码以同时使用嵌套数组和对象,如果你不需要数组部分功能,那么将它排除在外是很容易的,我会让你处理细节