0

Problem: I don't want to expose $myProperty, that is it shouldn't be public, but I need it to be public just for __toString():

class A
{
    protected $myProperty;

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

I know that ReflectionProperty class has a method named setAccessible(), but how I'm supposed to use it before returning the string?

EDIT: as per comments, I need compatibility with PHP 5.3.x, that is no JSonSerializable class.

gremo
  • 47,186
  • 75
  • 257
  • 421
  • Psst: http://php.net/JsonSerializable – hakre Dec 18 '12 at 00:46
  • 2
    I'd better implement [`JsonSerializable`](http://php.net/manual/en/jsonserializable.jsonserialize.php) interface in order to state clearly which fields will be serialized, and which not. – moonwave99 Dec 18 '12 at 00:47
  • I'd have to say that `setAccessible()` probably falls under the category of "evil magic that you should never use". It's interesting, but should never be necessary in production code. –  Dec 18 '12 at 00:47
  • @moonwave99 of course, BUT I need compatibility with 5.3.x. – gremo Dec 18 '12 at 00:49
  • @gremo well that's basically the same - you don't implement the interface, and you call the method explicitly when you need it ^^ – moonwave99 Dec 18 '12 at 00:50
  • @duskwuff can you explain better with it's evil? Reflection is evil for you? – gremo Dec 18 '12 at 00:50
  • Anyway my fav solution is to rely on [annotations](https://github.com/schmittjoh/metadata) when serializing: you take advantage of reflection but you don't mess with hardcoding inside the class itself. – moonwave99 Dec 18 '12 at 00:55
  • @Gremo: It's "evil" in that it breaks the contract of field protection. If the field isn't actually private, don't make it private. :) –  Dec 18 '12 at 01:16

2 Answers2

3

As per PHP 5.3 use get_object_vars inside the __toString() method:

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

Usage Demo:

class A
{
    protected $myProperty = 'hello';

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

echo new A; 

Output:

{"myProperty":"hello"}

Tip: Create the JsonSerializable interface your own and implement the jsonSerialize() method your own to be upwards compatible. Call the function when you need it and/or call it inside __toString():

public function __toString()
{
    return json_encode($this->jsonSerialize());
}
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Interesting... this will work because the protected property is in the scope, right? – gremo Dec 18 '12 at 00:52
  • Exactly. Will also give private properties. As well as with `(array) $this` but that one has unwanted side-effects so `get_object_vars` is better. – hakre Dec 18 '12 at 00:56
  • Curious, is `(object)` cast here necessary? – zerkms Dec 18 '12 at 01:04
  • @zerkms: technically not, because `json_encode` will it encode as json object because of non-numeric keys. Edited. (nice spot, thx) – hakre Dec 18 '12 at 01:20
0

Why don't you simply build a PHP stdClass object and then serialize it to JSON, since when you deserialize from JSON, that is exactly what you get anyway.

Maybe something like this:

public function __toString() {
   $return = new stdClass();
   $properties = get_object_vars($this);
   foreach ($properties as $key => $value) {
       $return->$key = $value;
   }
   return json_encode($return);
}
Mike Brant
  • 70,514
  • 10
  • 99
  • 103