TheEditor TheEditor - 3 months ago 13
JSON Question

Slim framework unable to encode to json with protected variables

Basically I was encoding a response with json and couldn't figure out why it kept returning the right number of array members but they were empty.

$app->get('/api/server_list', function ($request, $response, $args) {
$serverlist = new ServerListing($this->db);
$servers = $serverlist->getServers();
$newResponse = $response->withJson($servers);
return $newResponse;
});


This is the output of the above with an added print_r($servers)

[{},{}]Array
(
[0] => ServerEntity Object
(
[id:protected] => 1
[serverName:protected] => dc1.domain.com
)

[1] => ServerEntity Object
(
[id:protected] => 2
[serverName:protected] => dc2.domain.com
)

)


Here is the class code for ServerListing:

<?php

class ServerListing extends Listing
{
public function getServers() {
$sql = "SELECT * from servers";
$stmt = $this->db->query($sql);

$results = [];

while($row = $stmt->fetch()) {
$results[] = new ServerEntity($row);
}
return $results;
}
}


Here is ServerEntity:

<?php

class ServerEntity
{
public $id;
public $serverName;

public function __construct(array $data) {

if(isset($data['id'])) {
$this->id = $data['id'];
}

$this->serverName = $data['name'];
}

public function getId() {
return $this->id;
}
public function getServerName() {
return $this->serverName;
}

}


Only way it works is with public.

I understand public/private/protected. Though this is my first time with a framework and Object Oriented php.

Using the same database call in another route I can then pass the server list to a view and it works fine.

So I guess two questions.


  1. Why does the json encode fail?

  2. Am I doing something fundamentally wrong/ is there a better way to do this?


Answer

Slim's Response::withJson() doesn't do anything magic. It relies on the PHP function json_encode() to do the encoding. json_encode() also doesn't know any special trick. If you pass an object to it to encode it gets all the data it can get from it. And that means only its public properties because, well, this is how OOP works.

However, if you implement the JsonSerializable interface in a class then you can control what data is available to json_encode() when it comes to encode an object of that class.

For example:

class ServerEntity implements JsonSerializable
{
    private $id;
    private $serverName;

    // ... your existing code here

    public function jsonSerialize()
    {
        return array(
            'id'   => $this->id,
            'name' => $this->serverName,
        );
    }
}

Some test code:

echo(json_encode(new ServerEntity(array('id' => 7, 'name' => 'foo'))));

The output is:

{"id":7,"name":"foo"}