I've run into an odd problem and I'm not sure how to fix it. I have several classes that are all PHP implementations of JSON objects. Here' an illustration of the issue
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;
The output from this is
[{},{}]
When the desired output is
[{"foo":"bar"},{"foo":"bar"}]
The problem is that I was relying on the __toString() hook to do my work for me. But it can't, because the serialize that json_encode() uses won't call __toString(). When it encounters a nested object it simply serializes public properties only.
So, the question then become this: Is there a way I can develop a managed interface to JSON classes that both lets me use setters and getters for properties, but also allows me to get the JSON serialization behavior I desire?
If that's not clear, here's an example of an implementation that won't work, since the __set() hook is only called for the initial assignment
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;
I suppose I could also do something like this
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;
But then I would have to rely on the diligence of the other developers to use the setters - I can't force adherence programmtically with this solution.
---> EDIT <---
Now with a test of Rob Elsner's response
<?php
class a implements IteratorAggregate
{
public $foo = 'bar';
protected $bar = 'baz';
public function getIterator()
{
echo __METHOD__;
}
}
echo json_encode( new a );
When you execute this, you can see that the getIterator() method isn't ever invoked.