PHP:__ toString()和json_encode()不能很好地融合在一起

Pet*_*ley 11 php serialization json

我遇到了一个奇怪的问题,我不知道如何解决它.我有几个类都是JSON对象的PHP实现.这是'问题的一个例子

class A
{
    protected $a;

    public function __construct()
    {
        $this->a = array( new B, new B );
    }

    public function __toString()
    {
        return json_encode( $this->a );
    }
}

class B
{
    protected $b = array( 'foo' => 'bar' );

    public function __toString()
    {
        return json_encode( $this->b );
    }
}

$a = new A();

echo $a;
Run Code Online (Sandbox Code Playgroud)

这个输出是

[{},{}]
Run Code Online (Sandbox Code Playgroud)

所需的输出是

[{"foo":"bar"},{"foo":"bar"}]
Run Code Online (Sandbox Code Playgroud)

问题是我依靠__toString()钩子来为我做我的工作.但它不能,因为json_encode()使用的序列化不会调用__toString().遇到嵌套对象时,它只是序列化公共属性.

那么,问题就变成了这样:有没有办法可以开发一个JSON类的托管接口,它既可以让我使用setter和getter来获取属性,也可以让我获得我想要的JSON序列化行为?

如果这是不明确的,这里是一个实现的例子就不会工作,因为__set()钩子只要求初始分配

class a
{
    public function __set( $prop, $value )
    {
        echo __METHOD__, PHP_EOL;
        $this->$prop = $value;
    }

    public function __toString()
    {
        return json_encode( $this );
    }
}

$a = new a;
$a->foo = 'bar';
$a->foo = 'baz';

echo $a;
Run Code Online (Sandbox Code Playgroud)

我想我也可以这样做

class a
{
    public $foo;

    public function setFoo( $value )
    {
        $this->foo = $value;
    }

    public function __toString()
    {
        return json_encode( $this );
    }
}

$a = new a;
$a->setFoo( 'bar' );

echo $a;
Run Code Online (Sandbox Code Playgroud)

但后来我不得不依赖其他开发人员的勤奋使用setter - 我不能强制遵循这个解决方案的程序.

--->编辑<---

现在测试一下Rob Elsner的回应

<?php

class a implements IteratorAggregate 
{
    public $foo = 'bar';
    protected $bar = 'baz';

    public function getIterator()
    {
        echo __METHOD__;
    }
}

echo json_encode( new a );
Run Code Online (Sandbox Code Playgroud)

执行此操作时,您可以看到不会调用getIterator()方法.

Tiv*_*vie 27

答案较晚,但对于遇到同样问题的其他人可能会有用.

PHP <5.4.0 json_encode中,不会从对象调用任何方法.这对getIterator,__ serialize等有效...

但是,在PHP> v5.4.0中,引入了一个名为JsonSerializable的新接口.

它基本上控制了在该对象json_encode上调用时对象的行为.


小提琴(嗯,实际上是PHP CodePad,但同样的事情......)

示例:

class A implements JsonSerializable
{
    protected $a = array();

    public function __construct()
    {
        $this->a = array( new B, new B );
    }

    public function jsonSerialize()
    {
        return $this->a;
    }
}

class B implements JsonSerializable
{
    protected $b = array( 'foo' => 'bar' );

    public function jsonSerialize()
    {
        return $this->b;
    }
}


$foo = new A();

$json = json_encode($foo);

var_dump($json);
Run Code Online (Sandbox Code Playgroud)

输出:

string(29)"[{"foo":"bar"},{"foo":"bar"}]"