Skip to content
Theory · Files, namespaces and Composer · lesson 6 of 7

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
<?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:

  1. The associative array $user becomes a JSON object in curly braces, with the keys as strings in double quotes.
  2. The list ['php', 'sql'] becomes a JSON array in square brackets.
  3. The number 30 and the boolean false are written as they are: JSON has its own numbers, true, false and null.
  4. 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:

PHP
$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 sql

The 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 true a 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:

PHP
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:

PHP
$user = json_decode('{"name":"Anna"}');
echo $user['name'], "\n"; // ✗
TEXT
Fatal error: Uncaught Error: Cannot use object of type stdClass as array

json_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_encode writes a list as a JSON array and an array with other keys as an object; the flag JSON_UNESCAPED_UNICODE keeps Cyrillic as letters.
  • json_decode($json, true) returns arrays, and without true it returns stdClass objects read with ->.
  • Broken JSON gives null without flags and throws a JsonException with the flag JSON_THROW_ON_ERROR.
  • Data from a user must never go into unserialize; JSON is the format for exchanging data.