PHP json_encode class private members

I'm trying to JSON encode some objects in PHP, but I'm facing a problem: I want to encode data which is kept by a class private members. I found this piece of code to encode this object by calling an encode function like:

public function encodeJSON() 
{ 
    foreach ($this as $key => $value) 
    { 
        $json->$key = $value; 
    } 
    return json_encode($json); 
}

However, this only works if the object I want to encode does not contain other objects inside, which is the case. How can I do to encode not only the "outer" object, but encode as well any members that are objects too?

Answers


The best method to serialize an object with private properties is to implement the \JsonSerializable interface and then implement your own JsonSerialize method to return the data you require to be serialized.

<?php

class Item implements \JsonSerializable
{
    private $var;
    private $var1;
    private $var2;

    public function __construct()
    {
        // ...
    }

    public function jsonSerialize()
    {
        $vars = get_object_vars($this);

        return $vars;
    }
}

json_encode will now serialize your object correctly.


If you're using php 5.4 you can use the JsonSerializable interface: http://www.php.net/manual/en/class.jsonserializable.php

You just implement a jsonSerialize method in your class which returns whatever you want to be encoded.

Then when you pass your object into json_encode, it'll encode the result of jsonSerialize.


Anyway. You need create public method in your class to return all their fields json encoded

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

I think @Petah's got the best approach, but that way you lose properties that are array or object. So I added a function wich do that recursively:

function json_encode_private($object) {

    function extract_props($object) {
        $public = [];

        $reflection = new ReflectionClass(get_class($object));

        foreach ($reflection->getProperties() as $property) {
            $property->setAccessible(true);

            $value = $property->getValue($object);
            $name = $property->getName();

            if(is_array($value)) {
                $public[$name] = [];

                foreach ($value as $item) {
                    if (is_object($item)) {
                        $itemArray = extract_props($item);
                        $public[$name][] = $itemArray;
                    } else {
                        $public[$name][] = $item;
                    }
                }
            } else if(is_object($value)) {
                $public[$name] = extract_props($value);
            } else $public[$name] = $value;
        }

        return $public;
    }

    return json_encode(extract_props($object));
}

EDIT: Added is_object() check inside the array loop to avoid a get_class() exception in the next extract_props() call when the array elements are not objects, like strings or numbers.


public function jsonSerialize()
{
    $objectArray = [];
    foreach($this as $key => $value) {
        $objectArray[$key] = $value;
    }

    return json_encode($objectArray);
}

I personally think this is a way of doing it. It is similar to Petah's, except It keeps in line with encapsulation well, because the array is populated from the object.

Put this function in either your object or as a trait to be used by your object. To each their own though.


This would print a JSON with all of the properties (public, private and protected) of class foo:

$reflection = new ReflectionClass('Foo');
$properties = $reflection->getdefaultProperties();

echo json_encode($properties);

It would work from any context.


Using reflection you can json_encode private properties, although its not considered best practice:

function json_encode_private($object) {
    $public = [];
    $reflection = new ReflectionClass($object);
    foreach ($reflection->getProperties() as $property) {
        $property->setAccessible(true);
        $public[$property->getName()] = $property->getValue($object);
    }
    return json_encode($public);
}

E.g.

class Foo {
    public $a = 1;
    public $b = 2;
}
class Bar {
    private $c = 3;
    private $d = 4;
}

var_dump(json_encode(new Foo()));
var_dump(json_encode_private(new Bar()));

Outputs:

string(13) "{"a":1,"b":2}"
string(13) "{"c":3,"d":4}"

http://codepad.viper-7.com/nCcKYW


You can only encode an object's private members from within the class. As a side note though, does the json_enocde function not work for you? http://php.net/manual/en/function.json-encode.php


I think this may be a great case for the Usage of Traits

using the below guist I implemented jsonSerializable interface in multiple points of my app while keeping the code manageable

https://gist.github.com/zburgermeiszter/7dc5e65b06bb34a325a0363726fd8e14

trait JsonSerializeTrait
{
    function jsonSerialize()
    {
        $reflect = new \ReflectionClass($this);
        $props   = $reflect->getProperties(\ReflectionProperty::IS_STATIC | \ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE);

        $propsIterator = function() use ($props) {
            foreach ($props as $prop) {
                yield $prop->getName() => $this->{$prop->getName()};
            }
        };

        return iterator_to_array($propsIterator());
    }
}

then you just have to do

class YourClass implements JsonSerializable 
{
    use JsonSerializeTrait;

    ... normal encapsulated code...
}

Need Your Help

sql "LIKE" equivalent in django query

python sql django django-models django-queryset

What is the equivalent of this SQL statement in django?

Android Bluetooth Example

android bluetooth

Can anybody give me Android Bluetooth communication tutorial links or hints? Please don't tell me to refer to the BluetoothChat example, I can only understand how to discover and connect to devices...