My data arrives in the form of associative arrays. This works, but my code is a mess of nested arrays and I would like to start using proper OO/Objects to make this data easier to work with. I cannot change the way I receive this data, so I would like to find a clean way to convert the associative arrays into instances of my classes below.
I have these classes to model People in my application:
class Person {
/**
* @var string
*/
private $_name;
/**
* @var array[Dog]
*/
private $_dogs = array();
/**
* @var array[Hobby]
*/
private $_hobbies = array();
}
class Dog {
/**
* @var string
*/
private $_color;
/**
* @var string
*/
private $_breed;
}
class Hobby {
/**
* @var string
*/
private $_description;
/**
* @var int
*/
private $_cost;
}
My data (in JSON) looks like this:
'person': {
'name': 'Joe',
'dogs': [
{'breed': 'Husky', 'color': 'Black'},
{'breed': 'Poodle', 'color': 'Yellow'}
]
'hobbies': [
{'description': 'Skiing', 'cost': 500},
{'description': 'Running', 'cost': 0}
]
}
I can easily convert this JSON to an associative array using json_decode
, but the difficulty comes in converting each of the nested Hobby
and Pet
objects into the appropriate classes, and then when I want the associative array back, converting these objects into associative arrays again.
I can do all this by writing a to/from array function in each of my classes but that seems rather messy and prone to error. Is there a more straightforward way that I can quickly hydrate/dehydrate these objects?
This may not work perfectly (since i cant test it at the moment), but try something like this:
$data = json_decode($jsonData, TRUE);
$myObj = new Object();
foreach($data as $key => $val) {
$myObj->$key = $val;
}
I passed TRUE for second param because otherwise json_decode will return stdClass object. I want to handle it as an associative array with foreach.
I realize that I haven't given a name of a design pattern, but I can't answer that with any confidence. Here's another response of a similar question: PHP Design Pattern
If you are doing a lot of decoding/encoding with JSON (as you mention you need to go back and forth between associative arrays and objects), I would make sure there is a legitimate reason to convert to custom classes.
Example:
$person = json_decode($json);
echo $person->name;
echo $person->dogs[0]->breed;
$person->name = "Jim";
$json = json_encode($person);
If you want to continue with a custom class, it will take some work. See this question.
Add this to Hobby
public function fromArray($array){
if(isset($array['description'])){
$this->_description = $array['description'];
}
if(isset($array['cost'])){
$this->_cost = $array['cost'];
}
}
public function toArray(){
$array = array();
$array['description'] = $this->_description;
$array['cost'] = $this->_cost;
return $array;
}
And this to Dog:
public function fromArray($array){
if(isset($array['breed'])){
$this->_breed = $array['breed'];
}
if(isset($array['cost'])){
$this->_cost = $array['color'];
}
}
public function toArray(){
$array = array();
$array['breed'] = $this->_breed;
$array['color'] = $this->_color;
return $array;
}
and in Person class:
public function fromArray($array){
if(isset($array['name'])){
$this->_name = $array['name'];
}
if(isset($array['dogs'])){
foreach($array['dogs'] as $dogArray){
$dog = new Dog();
$dog->fromArray($dogArray);
$this->_dogs[] = $dog;
}
}
if(isset($array['hobbies'])){
foreach($array['hobbies'] as $hobbyArray){
$hobby = new Hobby();
$hobby->fromArray($hobbyArray);
$this->_hobbies[] = $hobby;
}
}
}
public function toArray(){
$array = array();
$array['name'] = $this->_name;
foreach($this->_dogs as $dogObj){
$array['dogs'][] = $dogObj->toarray();;
}
foreach($this->_hobbies as $hobbyObj){
$array['hobbies'][] = $hobbyObj->toarray();;
}
return $array;
}