Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

JsonSerializableインターフェース

jsViewsについて書こうと思ったんですが、ちょっと寄り道。。。

むー、つい最近まで知らなかった。。。PHP5.4.0から追加されたようですね。JsonSerializableインターフェースのドキュメントは以下のURLです。

オブジェクトをそのままjson_encodeしてJSONデータにしたい場合、publicなメンバー変数のみJSONデータに現れます。たとえば、以下のようなコードの場合、

<?php
namespace JsonSerializableTest;

class Customer
{
    public $id;
    protected $name;
    private $birthday;

    public function __construct($id, $name, \DateTime $birthday)
    {
        $this->id = $id;
        $this->name = $name;
        $this->birthday = $birthday;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getBirthday()
    {
        return $this->birthday;
    }
}
$obj = new Customer('1', 'foo', new \DateTime('1970-01-01'));
echo json_encode($obj, JSON_PRETTY_PRINT);

これを実行すると、メンバー変数"name"と"birthday"は出力されません。

{
    "id": "1"
}

ここで、PHP5.4.0から導入されたJsonSerializableインターフェースをimplementsし、定義されているjsonSerializeメソッドを実装することで、json_encodeする際に任意のデータを出力できるようになります。
たとえば、上記の非publicメンバーも出力する場合は以下のようなコードになります。

<?php
namespace JsonSerializableTest;

class Customer implements \JsonSerializable
{
    public $id;
    protected $name;
    private $birthday;

    public function __construct($id, $name, \DateTime $birthday)
    {
        $this->id = $id;
        $this->name = $name;
        $this->birthday = $birthday;
    }

    public function getBirthday()
    {
        return $this->birthday;
    }

    public function jsonSerialize() {
        $object = new \stdClass();
        $object->id = $this->id;
        $object->name = $this->name;
        $object->birthday = $this->birthday->format('Y/m/d');
        return $object;
    }
}
$obj = new Customer('1', 'foo', new \DateTime('1970-01-01'));
echo json_encode($obj, JSON_PRETTY_PRINT);

この実行は次のようになります。

{
    "id": "1",
    "name": "foo",
    "birthday": "1970\/01\/01"
}

いちいちメンバー変数を書くのが面倒な場合は、こんな感じでもOKです。

<?php
namespace JsonSerializableTest;

class Customer implements \JsonSerializable
{
       :

    public function jsonSerialize() {
        $object = new \stdClass();
        $class = new \ReflectionClass($this);
        foreach ($class->getProperties() as $property) {
            $property->setAccessible(true);
            $property_name = $property->getName();
            $object->$property_name = $property->getValue($this);
        }

        return $object;
    }
}

この場合は次のような感じになります。

{
    "id": "1",
    "name": "foo",
    "birthday": {
        "date": "1970-01-01 00:00:00",
        "timezone_type": 3,
        "timezone": "Asia\/Tokyo"
    }
}

追記(2012/10/25 18:50)

Reflectionが面倒な場合は、これでもOKです。

<?php
namespace JsonSerializableTest;

class Customer implements \JsonSerializable
{
       :

    public function jsonSerialize() {
        return (object)get_object_vars($this);
    }
}