Yesterday I found an interesting quirk while working with a code base that uses json_encode
and json_decode
to serialize data moving in and out of the database.
The benifits of using JSON over standard PHP serialization (for basic objects) are fairly obvious:
- Data portability
- Easier to parse by hand (manual database updates)
- Lighter weight in general
But there is one gotcha... Consider this example:
$php_struct = array(
"key" => 5,
"another" = "data",
);
$json_string = json_encode( $php_struct );
//...
$php_struct = json_decode( $json_string );
// array? Nope, this is an object
echo gettype($php_struct);
Expected Unexpected Behavior
The problem here is that most often when using a serialization method in/out of the database, it should be hidden and abstracted into the boilerplate database interaction. The expectation is that if you put one thing in, you get the same thing out. Which is not the case when feeding these json functions associative arrays.
The Array Flag
json_decode()
does provide a second parameter to tell it you want objects decoded as associative arrays, but again, this simply flips the problem on it's head. You encode an object and when it's decoded, you get an array back. It is still possible to put one thing in, and get a different thing out.
Solution?
The only solution I can think of is something like this...
Serialize
// $php_struct is our data
// Create a wrapper object
$obj = new stdClass;
// encode the actual data
$obj->data = json_encode( $php_struct );
// Store whether or not it is an array
$obj->is_array = is_array( $php_struct );
// encode for storage
$obj_json = json_encode( $obj );
save( $obj_json );
De-serialize
$obj_json = retrieve();
$obj = json_decode( $obj_json );
$php_struct = json_decode( $obj->data, $obj->is_array );