1

Lets begin with two small tests:


$original = [0 => 'a', 1 => 'b'];
var_dump((json_decode(json_encode($original))));

returns

array(2) { // array
    [0]=> // integer like original
        string(1) "a"
    [1]=> // integer like original
        string(1) "b"
}

So we can see here, that assoc parameter (second parameter in json_decode function) is not set (default is false), and pair json_decode-json_encode recovers original as it should.


$original = [1 => 'a', 2 => 'b'];
var_dump((json_decode(json_encode($original))));

returns

object(stdClass)#1 (2) { // object
    ["1"]=> // string, instead of integer
        string(1) "a"
    ["2"]=> // string, instead of integer
        string(1) "b"
}

Here again, assoc is false, but pair json_decode-json_encode can't recover original unless we explicitly set assoc into true.


Question: I am working on a custom serialization process (different from PHP serialize and unserialize functions). I decided to use json_decode-json_encode pair and I found that I can't rely on default settings, like assoc=false. Are you aware of any other pitfalls with json_ family functions that may lead me to a problem when I won't be able to recover original data and structure?

1 Answer 1

3

The JSON encoding for an array looks like:

[ element, element, element, ... ]

As you can see, there are no explicit indexes, so this encoding can only be used when the array contains consecutive numeric indexes starting from 0.

Any other array is encoded as an object, and object keys are always strings in JSON. When you decode an object with json_decode() it returns a PHP object if assoc is false, an associative array if it's true.

When you go through the JSON encoding process for an object, there's no way to tell whether the original array had numeric or string indexes. They'll always become strings in JSON.

Furthermore, when you use assoc = false, and the result is an object, the properties necessarily have to be strings, because PHP objects can't have numeric property names.

When you use assoc = false you recover the original because PHP itself doesn't distinguish between numbers and numeric strings as indexes in an array. If you do:

var_dump( array('1' => 'a', 2 => 'b'));

the result is:

array(2) {
  [1]=>
  string(1) "a"
  [2]=>
  string(1) "b"
}

As you can see, PHP automatically turned the string '1' into the number 1 when creating the array.

JSON was never intended to be used to encode objects in any language without information loss. It's designed as a simple format that facilitates communication between applications that may be written in different languages. So it abstracts away many of the details, and just supports basic arrays and objects. Other formats like XML and serialize allow more precision.

Sign up to request clarification or add additional context in comments.

3 Comments

Well, they could do JSON_NUMERIC_CHECK on the encode.
That only affects the values, not the keys.
Thanks. Well, the problem we had 3 options (an array with 3 elements) that was stored as JSON encoded string. Later we decided to get rid of first option, so we decoded the string -> deleted [0] element -> encoded the string and then faced this problem when array has turned into object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.