json_decode
Parses a JSON string and returns it as a PHP object, array, or scalar value.
json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0): mixed- Added in PHP 5.2.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$json | string | The JSON string to decode. Must be valid UTF-8. |
$associativeoptional | ?bool= null | true returns JSON objects as associative arrays, false returns them as stdClass objects, null defers to the JSON_OBJECT_AS_ARRAY flag. |
$depthoptional | int= 512 | Maximum nesting depth of the structure being decoded. Must be greater than 0 and at most 2147483647. |
$flagsoptional | int= 0 | Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE, JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY and JSON_THROW_ON_ERROR. |
Return value
mixedThe decoded value as stdClass, array, string, int, float, bool or null. Returns null if the JSON cannot be decoded or if the nesting is deeper than depth.
Errors
Throws JsonException when JSON_THROW_ON_ERROR is set and the string cannot be decoded, and ValueError when depth is outside the range 1 to 2147483647.
Changelog
- PHP 7.3.0JSON_THROW_ON_ERROR was added, so decoding can raise a JsonException instead of returning null.
- PHP 7.2.0The associative parameter became nullable, and JSON_INVALID_UTF8_IGNORE and JSON_INVALID_UTF8_SUBSTITUTE were added.
- PHP 7.1.0An empty JSON key ("") now decodes to an empty property name on the object instead of the property _empty_.
json_decode parses a UTF-8 JSON string and returns the matching PHP value. By default JSON objects come back as stdClass instances; passing true for the second argument returns associative arrays instead, which is usually what you want when the next thing you do is loop over the data or check keys with isset().
How JSON types map to PHP
| JSON | PHP (default) | PHP (associative) |
|---|---|---|
| object | stdClass | array |
| array | array | array |
| number | int or float | int or float |
| true / false / null | bool / null | bool / null |
Detecting failure
On failure the function returns null — but null is also the correct result for the perfectly valid input null. A null check is therefore not an error check. Either read json_last_error() straight after the call, or pass JSON_THROW_ON_ERROR so a malformed payload raises JsonException instead of quietly disappearing.
Reach for it whenever data arrives as text: an API response, a webhook body from php://input, a JSON column out of the database, or a config file. Numbers larger than PHP_INT_MAX silently become floats and lose precision unless you add JSON_BIGINT_AS_STRING.
Example
When to use it
- Turn an HTTP API response body into a PHP array before reading fields from it.
- Read a webhook payload from php://input and validate it before processing.
- Load a JSON config or fixture file from disk into an array with file_get_contents.
- Expand a JSON column fetched from MySQL or PostgreSQL back into PHP data.
Frequently asked questions
What is the difference between json_decode with true and without?
Without the second argument, JSON objects are decoded into stdClass instances that you read with the arrow operator, such as $data->name. Passing true decodes them into associative arrays that you read with $data['name'], which works with array functions like array_map and isset checks on missing keys.
Why does json_decode return null?
Either the string is not valid JSON, it is not valid UTF-8, it nests deeper than the depth limit, or it genuinely is the JSON value null. Call json_last_error_msg() immediately afterwards to tell which, or pass JSON_THROW_ON_ERROR so failures throw a JsonException.
How do I decode JSON into a specific class instead of stdClass?
json_decode cannot instantiate your own classes; it only ever produces stdClass or arrays. Decode to an array first and construct your object from it, or use a mapper library or a named constructor such as MyClass::fromArray($data).
More examples
Fail loudly instead of returning null
The trailing comma makes the string invalid JSON, so the call throws a JsonException carrying the message "Syntax error" rather than returning null. The final line prints "No error" — proof that JSON_THROW_ON_ERROR bypasses the json_last_error() state entirely, so you cannot mix the two styles.
<?php
try {
$data = json_decode('{"a":1,}', true, 512, JSON_THROW_ON_ERROR);
print_r($data);
} catch (JsonException $e) {
echo "Bad JSON: ", $e->getMessage(), "\n";
}
// Calls made with JSON_THROW_ON_ERROR do not touch the global error state.
echo json_last_error_msg(), "\n";Keeping large integers intact
The ID is larger than PHP_INT_MAX, so the default decode produces a float and the last digits are lost forever. With JSON_BIGINT_AS_STRING the same value comes back as the exact string "12345678901234567890", which is what you want for Twitter-style IDs, Snowflake IDs and 64-bit database keys.
<?php
$json = '{"id":12345678901234567890}';
$default = json_decode($json, true);
var_dump($default['id']);
$safe = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
var_dump($safe['id']);Limiting nesting depth
The first call caps nesting at 3 levels, so the 4-level payload fails and json_last_error_msg() reports "Maximum stack depth exceeded". Raising the limit to 10 decodes the same string successfully. Lowering depth is a cheap defence against hostile payloads designed to exhaust memory.
<?php
$deep = '{"a":{"b":{"c":{"d":1}}}}';
var_dump(json_decode($deep, true, 3));
echo json_last_error_msg(), "\n";
print_r(json_decode($deep, true, 10));
echo json_last_error_msg(), "\n";Decoding a JSON Lines stream
JSON Lines files hold one complete JSON document per line, so you decode each line separately rather than the whole file at once. This keeps memory flat for large exports, and JSON_THROW_ON_ERROR makes a corrupt line stop the loop instead of silently yielding null.
<?php
$lines = "{\"id\":1,\"ok\":true}\n{\"id\":2,\"ok\":false}\n";
file_put_contents('events.jsonl', $lines);
foreach (file('events.jsonl', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$row = json_decode($line, true, 512, JSON_THROW_ON_ERROR);
echo $row['id'], ' => ', var_export($row['ok'], true), "\n";
}
unlink('events.jsonl');
Discussion