开发者

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 i开发者_如何学编程s 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?


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.


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...
}


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.


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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜