Using json_encode on objects in PHP (regardless of scope)
Asked Answered
H

9

88

I'm trying to output lists of objects as json and would like to know if there's a way to make objects usable to json_encode? The code I've got looks something like

$related = $user->getRelatedUsers();
echo json_encode($related);

Right now, I'm just iterating through the array of users and individually exporting them into arrays for json_encode to turn into usable json for me. I've already tried making the objects iterable, but json_encode just seems to skip them anyway.

edit: here's the var_dump();

php > var_dump($a);
object(RedBean_OODBBean)#14 (2) {
  ["properties":"RedBean_OODBBean":private]=>
  array(11) {
    ["id"]=>
    string(5) "17972"
    ["pk_UniversalID"]=>
    string(5) "18830"
    ["UniversalIdentity"]=>
    string(1) "1"
    ["UniversalUserName"]=>
    string(9) "showforce"
    ["UniversalPassword"]=>
    string(32) ""
    ["UniversalDomain"]=>
    string(1) "0"
    ["UniversalCrunchBase"]=>
    string(1) "0"
    ["isApproved"]=>
    string(1) "0"
    ["accountHash"]=>
    string(32) ""
    ["CurrentEvent"]=>
    string(4) "1204"
    ["userType"]=>
    string(7) "company"
  }
  ["__info":"RedBean_OODBBean":private]=>
  array(4) {
    ["type"]=>
    string(4) "user"
    ["sys"]=>
    array(1) {
      ["idfield"]=>
      string(2) "id"
    }
    ["tainted"]=>
    bool(false)
    ["model"]=>
    object(Model_User)#16 (1) {
      ["bean":protected]=>
      *RECURSION*
    }
  }
}

and here's what json_encode gives me:

php > echo json_encode($a);
{}

I ended up with just this:

    function json_encode_objs($item){   
        if(!is_array($item) && !is_object($item)){   
            return json_encode($item);   
        }else{   
            $pieces = array();   
            foreach($item as $k=>$v){   
                $pieces[] = "\"$k\":".json_encode_objs($v);   
            }   
            return '{'.implode(',',$pieces).'}';   
        }   
    }   

It takes arrays full of those objects or just single instances and turns them into json - I use it instead of json_encode. I'm sure there are places I could make it better, but I was hoping that json_encode would be able to detect when to iterate through an object based on its exposed interfaces.

Hamza answered 15/1, 2011 at 2:46 Comment(3)
What is the output of var_dump($related) and echo json_encode($related)?Commute
'objects' by definition are not iterable.Tani
By iterable, I mean that the objects implement the interface IteratorAggregate and that I can iterate over them with a simple foreach.Hamza
B
8

In RedBeanPHP 2.0 there is a mass-export function which turns an entire collection of beans into arrays. This works with the JSON encoder..

json_encode( R::exportAll( $beans ) );
Bioplasm answered 20/5, 2011 at 7:32 Comment(1)
Also, in RB 2.0, if you cast a bean to a string you'll get the JSON representation.Bioplasm
T
168

All the properties of your object are private. aka... not available outside their class's scope.

Solution for PHP >= 5.4

Use the new JsonSerializable Interface to provide your own json representation to be used by json_encode

class Thing implements JsonSerializable {
    ...
    public function jsonSerialize() {
        return [
            'something' => $this->something,
            'protected_something' => $this->get_protected_something(),
            'private_something' => $this->get_private_something()
        ];
    }
    ...
}

Solution for PHP < 5.4

If you do want to serialize your private and protected object properties, you have to implement a JSON encoding function inside your Class that utilizes json_encode() on a data structure you create for this purpose.

class Thing {
    ...
    public function to_json() {
        return json_encode(array(
            'something' => $this->something,
            'protected_something' => $this->get_protected_something(),
            'private_something' => $this->get_private_something()                
        ));
    }
    ...
}

A more detailed writeup

Tani answered 15/1, 2011 at 2:50 Comment(7)
json_encode() is just outputting "{}" when I pass it these objects. It's not a matter of having my arrays be defined associative or not, unfortunately.Hamza
I believe he is talking about the $a->properties array, which looks like it contains the data you're after. Because that is a private variable, it will be ignored by json_encode(), and cause json_encode() to output '{}' as you are describing.Fenugreek
I was hoping that json_encode() would be able to see exposed methods to define some sort of behavior involving objects without externally accessible properties. It seems that this cannot yet be done, so I wrote up a function to recursively process these lists of objects, instead.Hamza
You can see another solution at jrgns.net/content/…Coming
for completeness, as mentioned by @Jrgns, you can return get_object_vars( $this ); to dump all the properties.Propitiatory
implementing JsonSerializable is an elegant way to do thisIncredible
This should be the accepted answer. Private fields are according to the Encapsulation OOP principle so using JsonSerializable interface is the best way to solve the problemDelanty
I
50

In PHP >= 5.4.0 there is a new interface for serializing objects to JSON : JsonSerializable

Just implement the interface in your object and define a JsonSerializable method which will be called when you use json_encode.

So the solution for PHP >= 5.4.0 should look something like this:

class JsonObject implements JsonSerializable
{
    // properties

    // function called when encoded with json_encode
    public function jsonSerialize()
    {
        return get_object_vars($this);
    }
}
Ioab answered 8/5, 2012 at 15:2 Comment(4)
To echo the JSON array, return json_encode($result) where $result = get_object_vars($this);Gangrene
This should be the accepted answer - automatically works with any class as get_object_vars will iterate all the properties.Defile
I'm not sure what has changed in PHP or my code, but no matter what I do lately get_object_vars($this) disregards the scope of $this and refuses to introspect on the private members of object. When all members are private, I get an empty array result. I'm using PHP 5.6.31. Is there some requirement for getting get_object_vars($this) to recognize scope?Rajiv
I don't think anything changed for get_object_vars. It was always only returning properties which were accessible. Thus when calling from within an object you'll get all privates and from outside you don't. See php.net/get_object_vars#example-6296Nisus
B
8

In RedBeanPHP 2.0 there is a mass-export function which turns an entire collection of beans into arrays. This works with the JSON encoder..

json_encode( R::exportAll( $beans ) );
Bioplasm answered 20/5, 2011 at 7:32 Comment(1)
Also, in RB 2.0, if you cast a bean to a string you'll get the JSON representation.Bioplasm
G
5

Following code worked for me:

public function jsonSerialize()
{
    return get_object_vars($this);
}
Grouper answered 31/3, 2014 at 12:55 Comment(1)
Emh. Maybe it's json.encode(get_object_vars($this))?Shrunk
W
2

I didn't see this mentioned yet, but beans have a built-in method called getProperties().

So, to use it:

// What bean do we want to get?
$type = 'book';
$id = 13;

// Load the bean
$post = R::load($type,$id);

// Get the properties
$props = $post->getProperties();

// Print the JSON-encoded value
print json_encode($props);

This outputs:

{
    "id": "13",
    "title": "Oliver Twist",
    "author": "Charles Dickens"
}

Now take it a step further. If we have an array of beans...

// An array of beans (just an example)
$series = array($post,$post,$post);

...then we could do the following:

  • Loop through the array with a foreach loop.

  • Replace each element (a bean) with an array of the bean's properties.

So this...

foreach ($series as &$val) {
  $val = $val->getProperties();
}

print json_encode($series);

...outputs this:

[
    {
        "id": "13",
        "title": "Oliver Twist",
        "author": "Charles Dickens"
    },
    {
        "id": "13",
        "title": "Oliver Twist",
        "author": "Charles Dickens"
    },
    {
        "id": "13",
        "title": "Oliver Twist",
        "author": "Charles Dickens"
    }
]

Hope this helps!

Whispering answered 30/6, 2013 at 18:3 Comment(0)
D
1

I usually include a small function in my objects which allows me to dump to array or json or xml. Something like:

public function exportObj($method = 'a')
{
     if($method == 'j')
     {
         return json_encode(get_object_vars($this));
     }
     else
     {
         return get_object_vars($this);
     }
}

either way, get_object_vars() is probably useful to you.

Dispensation answered 15/1, 2011 at 3:15 Comment(2)
I can just use json_encode($thing->export()); to give me the json I want, but that doesn't work as well when I've got arrays of them.Hamza
Then you can convert the array of objects into an array of arrays with something like for each($objArray as $key => $obj){$arrArray[$key] = $obj->export());} json_encode($arrArray); or you could do an array_map with get_object_vars().Dispensation
G
0
$products=R::findAll('products');
$string = rtrim(implode(',', $products), ',');
echo $string;
Groundhog answered 28/9, 2015 at 19:13 Comment(0)
A
0

Here is my way:

function xml2array($xml_data)
{
    $xml_to_array = [];

    if(isset($xml_data))
    {
        if(is_iterable($xml_data))
        {
            foreach($xml_data as $key => $value)
            {
                if(is_object($value))
                {
                    if(empty((array)$value))
                    {
                        $value = (string)$value;
                    }
                    else
                    {
                        $value = (array)$value;
                    }
                    $value = xml2array($value);
                }
                $xml_to_array[$key] = $value;
            }
        }
        else
        {
            $xml_to_array = $xml_data;
        }
    }

    return $xml_to_array;
}
Anamorphic answered 15/8, 2018 at 1:6 Comment(0)
G
-1

for an array of objects, I used something like this, while following the custom method for php < 5.4:

$jsArray=array();

//transaction is an array of the class transaction
//which implements the method to_json

foreach($transactions as $tran)
{
    $jsArray[]=$tran->to_json();
}

echo json_encode($jsArray);
Gyrostatics answered 27/3, 2014 at 16:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.