cj5
cj5

Reputation: 795

PHP __toArray() or __toObject() override?

Is there an equivalent to get a reorganized standardized object from a normal class? Something that works along the same lines as PHP's __toString() override method.

Okay, so I have this method that grabs a bunch of stations, and returns an object model, which handles a bunch of other methods to get other related data. So in this instance when I call the object that contains the locations "$locations" I want to get back either a flat associative array of object properties, or an array of objects that I can easily encode to JSON. If I get an array of location objects back, I just want $location to be directly converted to a JSON string. Just like if I were to refer to $location as a location object that contained __toString() and it would automatically produce a string representation. In this case I want an standard object or array, and not a string. Is there a way to do this?

Code sample below:

public function stnSearch() {
    $locations = DBO::getInstance()->query("
        SELECT " . DBO_Location::COLUMNS . "
        FROM " . DBO_Location::TABLE_NAME . " AS a
        WHERE a.title LIKE '%" . $_REQUEST['query'] . "%'
    ")->fetchAll(PDO::FETCH_CLASS, DBO_Location::MODEL);

    Util::debug($locations); // want this to produce a standard object for each model without having to do an additional loop

    exit();
}

Upvotes: 3

Views: 11305

Answers (2)

rjmunro
rjmunro

Reputation: 28056

In php 5.4 and above, if your class impliments JsonSerializable, you can add a jsonSerialize method that will be called by json_encode:

<?php
class MyClass implements JsonSerializable
{
    public $foo;

    public function jsonSerialize() {
        return array(
            "foo"=>$this->foo,
            "name"=>"MyClass"
        );
    }
}

$x = new MyClass();
$x->foo = "hello";
echo json_encode($x);

Will print:

{"foo":"hello","name":"MyClass"}

Upvotes: 14

cj5
cj5

Reputation: 795

Thanks for the feedback everyone! I ended up having to create a standard method in each class (one for toArray(), and one for toJSON()). This is not the desired solution, but it will have to do.

The toArray() method flattens out the complex class so that the array has properties available to either toObject() or toJSON() to digest. For instance I had a few methods that format data for output to HTML, and those do not automatically set to a local property in the class, so I need to set that up manually. via the method I mentioned above.

toArray() example:

public static function toArray($logs) {
    $b = new ArrayObject();

    $b->offsetSet('id', $logs->getId());
    $b->offsetSet('frequency', $logs->getFrequency());
    $b->offsetSet('formatted_frequency', number_format($logs->getFrequency(), 2, '.', ''));
    $b->offsetSet('mode', $logs->getMode());
    $b->offsetSet('time_on', $logs->getTimeOn()->format(self::JSON_DATE_FORMAT));
    $b->offsetSet('description', $logs->getDescription());
    $b->offsetSet('receive_location', $logs->receiveCoordinates()->toArray());

    ...

    return $b->getArrayCopy();
}

to get JSON object:

public static function toJSON($logs) {
    $b = self::toArray($logs);

    return json_encode($b);
}

Again this was not the desired result, but it gets the job done. Ideally I would love to have had a way to establish a method in the parent class that could be overridden, if there were extraneous properties that needed handling in a child class.

Upvotes: 4

Related Questions