In PHP, what does json_decode() return for a JSON object when its associative argument is omitted, and what changes when it is true?
answer
- objects vs arrays on the PHP side
- stdClass by default
- arrow access vs bracket access
- JSON arrays are PHP arrays either way
- JSON_OBJECT_AS_ARRAY is the flag form
basics
~10 sBy default json_decode() turns every JSON object into a stdClass object, read with ->; with the associative argument true, objects become associative arrays, read with []. JSON arrays become PHP arrays in both modes.
solid answer
~30 s`json_decode($json)` returns PHP values: strings, ints, floats, bools and `null` map directly, JSON arrays become indexed PHP arrays, and JSON **objects** become `stdClass` instances by default, so you read `$data->user->name`. Passing `true` as the second argument, `$associative`, decodes every object at every level as an **associative array** instead, so you read `$data['user']['name']`. The flag `JSON_OBJECT_AS_ARRAY` does the same, but an explicit `true` or `false` in `$associative` overrides it; only `null` (the default) lets the flag decide. Associative arrays are the common choice for payloads you feed into array functions; objects keep the JSON object-versus-array distinction that arrays lose.
code
php · 15 lines<?php
declare(strict_types=1);
$json = '{"member":{"name":"Ana","tags":["board","editor"]}}';
$asObject = json_decode($json);
var_dump($asObject->member->name); // string(3) "Ana"
var_dump($asObject->member->tags); // array(2) - JSON arrays stay arrays
$asArray = json_decode($json, true);
var_dump($asArray['member']['name']); // string(3) "Ana"
// false beats the flag; this still returns stdClass objects
$still = json_decode($json, false, 512, JSON_OBJECT_AS_ARRAY);
var_dump($still instanceof stdClass); // bool(true)go deeper
Recall that the default gives stdClass objects read with -> and that passing true gives associative arrays read with brackets.
Explain that the switch applies at every depth, how JSON_OBJECT_AS_ARRAY interacts with it, and what information array mode loses.
Choose the decode mode per boundary: arrays for validation pipelines, objects where empty-object versus empty-list must survive a round trip.
Set a codebase convention for decoding external payloads and for mapping them into typed objects, so every boundary does not invent its own.
## The signature In PHP 8.5, `json_decode()` is declared as: ```php json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0): mixed ``` It parses a JSON text and returns the matching PHP value. The return type is `mixed` because the top-level JSON value can be anything: `json_decode('5')` returns the int `5`, `json_decode('"hi"')` the string `hi`, `json_decode('[1,2]')` an array. ## How each JSON type maps | JSON value | PHP value (default) | PHP value with `$associative = true` | |---|---|---| | object `{"a":1}` | `stdClass` with property `a` | `['a' => 1]` | | array `[1,2]` | `[1, 2]` (indexed array) | `[1, 2]` | | string | `string` | `string` | | integer / fraction | `int` / `float` | `int` / `float` | | `true` / `false` / `null` | `bool` / `null` | `bool` / `null` | Two points trip people up: - **JSON arrays are always PHP arrays.** The `$associative` switch affects objects only. - **The switch is deep.** It applies to every object at every nesting level, not just the top one. ## Reading the result With the default, you navigate with the object operator: ```php $order = json_decode('{"id":7,"lines":[{"sku":"A1"}]}'); echo $order->lines[0]->sku; // A1 ``` With `true`, you navigate with brackets: ```php $order = json_decode('{"id":7,"lines":[{"sku":"A1"}]}', true); echo $order['lines'][0]['sku']; // A1 ``` Mixing them up gives the classic errors: `Cannot use object of type stdClass as array` when you bracket an object, or a warning about reading a property on an array when you arrow into an array. ## The flag form and who wins `JSON_OBJECT_AS_ARRAY` in `$flags` requests the same array decoding. The extension's source spells out the rule: an explicit boolean `$associative` overrides the flag. So: 1. `json_decode($j)` gives objects; 2. `json_decode($j, null, 512, JSON_OBJECT_AS_ARRAY)` gives arrays; 3. `json_decode($j, false, 512, JSON_OBJECT_AS_ARRAY)` gives objects, because `false` wins. Named arguments keep this readable: `json_decode($j, flags: JSON_THROW_ON_ERROR)`. ## Choosing between them - **Arrays** fit most application code: they work with `array_map()`, `array_column()`, destructuring and `isset($a['key'])`, and they are what most validation code expects. - **Objects** keep information that arrays drop: an empty JSON object decodes to an empty `stdClass`, which encodes back to `{}`, while with `true` it decodes to `[]` and encodes back as `[]`. - **Neither** gives you a typed domain object. `json_decode()` never calls a constructor or fills a class of your choosing; mapping into your own classes is a separate step. ## Keys that look like numbers JSON object keys are strings. In array mode, PHP applies its normal array-key rules, so `{"10":"x"}` becomes `[10 => 'x']` with an int key. In object mode the property is named `10` and must be read as `$obj->{'10'}`. ## Depth and flags in the same call The third and fourth parameters are easy to mix up because `$depth` comes before `$flags`: - `json_decode($j, true, 512, JSON_THROW_ON_ERROR)` is correct; - `json_decode($j, true, JSON_THROW_ON_ERROR)` passes the flag's integer value as the **depth**, so errors are not thrown at all; - `json_decode($j, true, flags: JSON_THROW_ON_ERROR)` avoids the problem with a named argument. `$depth` (default 512) is the maximum nesting of arrays and objects; deeper input fails with `JSON_ERROR_DEPTH`. ## Quick self-test 1. What type is `json_decode('{"a":[]}')->a`? An array, because JSON arrays are always PHP arrays. 2. What does `json_decode('{"a":{}}', true)['a']` hold? An empty array. 3. How do you read key `first-name` from an object result? `$obj->{'first-name'}`, since the name is not a valid identifier.
- What does json_decode('{}', true) re-encode to with json_encode(), and why does it matter?It decodes to an empty PHP array, and `json_encode([])` produces `[]`. The empty object has become an empty list, which breaks a consumer that expects an object. Decoding with the default object mode keeps an empty `stdClass`, which encodes back to `{}`.
- Does json_decode() ever create an instance of your own class?No. It only produces scalars, arrays and `stdClass` objects. Turning the result into a domain object is your code's job, for example a named constructor that reads the array and validates each field.
saying these in an interview costs you the question
- Thinking JSON arrays decode to stdClass without the associative flag
- Believing the associative argument only affects the top-level object
- Expecting json_decode() to hydrate a class of your choosing
- Assuming JSON_OBJECT_AS_ARRAY beats an explicit false argument
- Saying arrays and objects are interchangeable after decoding