JSON: json_encode and json_decode
When libraries exchange books, they write requests on a shared form. Each library arranges its books its own way, but every library understands the form. Programs need such a form too: a PHP site hands data to a JavaScript page, a mobile app, a Python program.
As you already know, the json_encode function writes an array as JSON, a text format programs use to exchange data. In this lesson we'll look at how JSON is built, how to read it back and what to do when broken text arrives.
An array to JSON
<?php
$user = ['name' => 'Анна', 'age' => 30, 'admin' => false, 'tags' => ['php', 'sql']];
echo json_encode($user), "\n"; // {"name":"\u0410\u043d\u043d\u0430","age":30,"admin":false,"tags":["php","sql"]}
echo json_encode($user, JSON_UNESCAPED_UNICODE), "\n"; // {"name":"Анна","age":30,"admin":false,"tags":["php","sql"]}
echo json_encode([1 => 20]), "\n"; // {"1":20}Let's see what each value turns into:
- The associative array
$userbecomes a JSON object in curly braces, with the keys as strings in double quotes. - The list
['php', 'sql']becomes a JSON array in square brackets. - The number
30and the booleanfalseare written as they are: JSON has its own numbers,true,falseandnull. - The array
[1 => 20]is not a list, since its keys don't start at zero, so it becomes an object too.
By default json_encode writes Cyrillic as codes like \u0410. The program on the other side reads them correctly, but they are hard for a person to read.
The flag JSON_UNESCAPED_UNICODE keeps the letters as they are. Another flag, JSON_PRETTY_PRINT, spreads JSON over lines with indentation, so a person can look it over.
Back from JSON: json_decode
The json_decode function reads JSON and returns a PHP value. What exactly it returns depends on the second argument:
$json = '{"name":"Anna","age":30,"tags":["php","sql"]}';
$obj = json_decode($json);
$arr = json_decode($json, true);
echo get_class($obj), "\n"; // stdClass
echo $obj->name, ' ', $obj->tags[1], "\n"; // Anna sql
echo $arr['name'], ' ', $arr['tags'][1], "\n"; // Anna sqlThe two calls differ like this:
- without the second argument a JSON object becomes an object of the built-in class
stdClass, with a property for each JSON key, read with->; - with the argument
truea JSON object becomes an associative array, and you read the values with['name'].
A JSON array becomes a PHP list in both cases.
Most code writes json_decode($json, true): arrays are more familiar, and all the functions from the arrays theme work on them.
Here the form picture stops working. The form has room only for text, numbers and lists, not for an object's class. That is why json_decode cannot return your User object—only a faceless stdClass or an array.
Broken JSON
In JSON, keys must be in double quotes. The string {name: "Anna"} is not JSON anymore:
var_dump(json_decode('{name: "Anna"}')); // NULL
try {
json_decode('{name: "Anna"}', true, flags: JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n"; // JsonException: Syntax error
}Without flags json_decode silently returns null. But null can also be a correct answer: the string 'null' is JSON too. From the null alone, an error can't be told apart from such a value.
That is why the flag JSON_THROW_ON_ERROR is safer: with it, broken text throws a JsonException. The named argument flags: skips the third parameter, which isn't needed here.
PHP also has a format of its own—the functions serialize and unserialize. It stores objects together with their class, but only PHP can read it.
Never pass data from a user to unserialize: such a string can create an object of any class in your project, and that is a well-known security hole. How JSON differs from serialize is a common interview question; for exchanging data, use JSON.
Common mistake
JSON was read without true, and the values are taken as from an array:
$user = json_decode('{"name":"Anna"}');
echo $user['name'], "\n"; // ✗Fatal error: Uncaught Error: Cannot use object of type stdClass as arrayjson_decode without the second argument returned a stdClass object, and an object can't be read with square brackets. The fix is json_decode('{"name":"Anna"}', true) or reading through the arrow: $user->name.
Key points
json_encodewrites a list as a JSON array and an array with other keys as an object; the flagJSON_UNESCAPED_UNICODEkeeps Cyrillic as letters.json_decode($json, true)returns arrays, and withouttrueit returnsstdClassobjects read with->.- Broken JSON gives
nullwithout flags and throws aJsonExceptionwith the flagJSON_THROW_ON_ERROR. - Data from a user must never go into
unserialize; JSON is the format for exchanging data.