PHP and JSON

Convert PHP arrays to JSON and back, read JSON from APIs and files, and send JSON responses from your own simple API.

Lesson 16 of 86Intermediate17 min read

JSON (JavaScript Object Notation) is the language web services use to talk to each other. When a weather app asks a server for today's forecast, when a shop's JavaScript loads more products without refreshing the page, or when a payment service reports that a payment succeeded, the data almost always travels as JSON.

JSON looks a lot like PHP's arrays: objects with named keys in curly braces, lists in square brackets, plus strings, numbers, true, false and null. PHP converts between the two with just two functions: json_encode() turns PHP data into JSON text, and json_decode() turns JSON text back into PHP data.

In this lesson you'll encode and decode JSON, handle invalid JSON safely, read JSON from a file and a web API, and write a tiny API endpoint of your own that returns JSON for JavaScript to use. It ties together the arrays and file handling lessons.

json_encode: PHP to JSON

PHP
$product = ['name' => 'Desk lamp', 'price' => 24.5, 'in_stock' => true];
echo json_encode($product);
// {"name":"Desk lamp","price":24.5,"in_stock":true}
  • Associative arrays become JSON objects { }; indexed arrays (0, 1, 2...) become JSON arrays [ ].
  • true, false and null become their JSON equivalents.
  • Add flags for nicer output: JSON_PRETTY_PRINT adds line breaks and indentation, and JSON_UNESCAPED_UNICODE and JSON_UNESCAPED_SLASHES keep characters like é and / readable.

Combine flags with |: json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).

json_decode: JSON to PHP

PHP
$json = '{"name":"Ana","scores":[82,91]}';
$data = json_decode($json, true);
echo $data['name'];        // Ana
echo $data['scores'][1];   // 91

The second argument, true, gives you associative arrays, which most PHP code finds easiest. Without it, objects become stdClass objects and you read them with arrows: $data->name. Pick one style and use it consistently.

Objects, empty arrays and JsonSerializable

json_encode turns an object into a JSON object using only its public properties; private and protected ones are left out. To control exactly what an object looks like as JSON, implement the JsonSerializable interface:

PHP
class Product implements JsonSerializable {
    public function __construct(private string $name, private float $price) {}

    public function jsonSerialize(): array {
        return ['name' => $this->name, 'price' => round($this->price, 2)];
    }
}

echo json_encode(new Product('Pen', 1.2));   // {"name":"Pen","price":1.2}

Empty arrays need a little care. PHP can't tell whether an empty array is meant as a list or an object, so json_encode([]) gives []. If the receiving program expects an object, use (object) [] or the JSON_FORCE_OBJECT flag, both of which give {}. Clients written in strongly typed languages often break when the same field is sometimes [] and sometimes {}.

Handling invalid JSON

JSON from outside your program might be broken or incomplete. By default json_decode simply returns null, which is easy to miss. The modern, safer way is to ask PHP to throw an exception:

PHP
try {
    $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    echo "Invalid JSON: " . $e->getMessage();
}

The 512 is the maximum nesting depth, which you'll rarely need to change. Exceptions are covered fully in the exceptions lesson.

Calling an API and returning JSON

Reading JSON from another service can be as simple as file_get_contents($url), although real projects usually use the cURL extension or a library such as Guzzle for timeouts and headers.

To build your own small API endpoint, set the right header and echo JSON:

PHP
header('Content-Type: application/json');
echo json_encode(['status' => 'ok', 'items' => $items]);

JavaScript on your page can then load it with fetch('/api/products.php'), exactly as in the JavaScript fetch lesson. Use http_response_code(404) or similar to signal errors properly.

PHP JSON Syntax

JSON functions

$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

header('Content-Type: application/json');
echo json_encode(['data' => $items]);

PHP JSON Summary

  • JSON is the standard text format for exchanging data between programs.
  • json_encode turns PHP arrays into JSON; flags like JSON_PRETTY_PRINT format it.
  • json_decode($json, true) gives associative arrays; without true you get objects.
  • Use JSON_THROW_ON_ERROR and catch JsonException for invalid JSON.
  • Send Content-Type: application/json when returning JSON from an endpoint.

PHP JSON Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Encoding a list of products

PHP
<?php
$products = [
    ['name' => 'Pen', 'price' => 1.2, 'tags' => ['stationery']],
    ['name' => 'Café mug', 'price' => 8.5, 'tags' => []],
];

echo json_encode($products), "\n\n";
echo json_encode($products[1], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Output
[{"name":"Pen","price":1.2,"tags":["stationery"]},{"name":"Caf\u00e9 mug","price":8.5,"tags":[]}]

{
    "name": "Café mug",
    "price": 8.5,
    "tags": []
}
Line-by-line explanation
  1. Lines 2 to 5An indexed array of associative arrays becomes a JSON array of objects.
  2. Line 7By default, non-English characters are escaped as \u codes.
  3. Line 8The flags make the output readable and keep é as it is.
Example 2

Decoding and using data

PHP
<?php
$json = '{"city":"Lisbon","days":[{"day":"Mon","temp":24},{"day":"Tue","temp":27},{"day":"Wed","temp":22}]}';

$forecast = json_decode($json, true);
$temps = array_column($forecast['days'], 'temp');

echo "Forecast for {$forecast['city']}\n";
foreach ($forecast['days'] as $d) {
    echo "{$d['day']}: {$d['temp']}°C\n";
}
echo "Warmest: " . max($temps) . "°C";
Output
Forecast for Lisbon
Mon: 24°C
Tue: 27°C
Wed: 22°C
Warmest: 27°C
Line-by-line explanation
  1. Line 4true turns every JSON object into an associative array.
  2. Line 5array_column pulls the temp value out of each day.
  3. Lines 8 to 10Nested data is reached with one key after another.
Example 3

A tiny JSON API endpoint

The browser requested /api/products.php?max=10.

PHP
<?php
// api/products.php
header('Content-Type: application/json');

$products = [
    ['name' => 'Pen', 'price' => 1.2],
    ['name' => 'Notebook', 'price' => 3.5],
    ['name' => 'Lamp', 'price' => 24.5],
];

$max = filter_var($_GET['max'] ?? '', FILTER_VALIDATE_FLOAT);
if ($max === false) {
    http_response_code(400);
    echo json_encode(['error' => 'max must be a number']);
    exit;
}

$cheap = array_values(array_filter($products, fn($p) => $p['price'] <= $max));
echo json_encode(['count' => count($cheap), 'data' => $cheap]);
Output
{"count":2,"data":[{"name":"Pen","price":1.2},{"name":"Notebook","price":3.5}]}
Line-by-line explanation
  1. Line 3Tell the browser it's receiving JSON.
  2. Lines 11 to 16Validate the input and return a 400 error in JSON if it's wrong.
  3. Line 18array_filter keeps cheap products; array_values renumbers them so they encode as a JSON array.

Common PHP JSON Mistakes

Forgetting true in json_decode

Don't
$data = json_decode($json);
echo $data['name'];       // Error: cannot use object as array
Do
$data = json_decode($json, true);
echo $data['name'];

Ignoring invalid JSON

Don't
$data = json_decode($input, true);
echo count($data['items']);     // fails confusingly if $input was broken
Do
try {
    $data = json_decode($input, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    http_response_code(400);
    exit(json_encode(['error' => 'Invalid JSON']));
}

Filtered arrays turning into objects

Don't
echo json_encode(array_filter([1, 5, 8], fn($n) => $n > 2));   // {"1":5,"2":8}
Do
echo json_encode(array_values(array_filter([1, 5, 8], fn($n) => $n > 2)));   // [5,8]

array_filter keeps the original keys, so the array is no longer 0, 1, 2 and encodes as an object.

PHP JSON in Real Projects

JSON in PHP projects

Shops send order data to payment services as JSON, mobile apps talk to PHP back ends through JSON APIs, and WordPress has a built-in REST API that returns posts and pages as JSON. Configuration files and translation files are also often stored as JSON and loaded with json_decode.

PHP JSON FAQ

How do I read JSON sent in a request body?

JSON posted by JavaScript's fetch or another API doesn't appear in $_POST. Read the raw body with file_get_contents('php://input') and decode it: $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);. Then validate the fields as you would form input.

Why does json_encode return false?

Most often because a string contains invalid UTF-8, for example text read from an old file in another encoding. json_last_error_msg() explains the problem, and JSON_THROW_ON_ERROR turns it into an exception. Convert the text to UTF-8 with mb_convert_encoding, or use JSON_INVALID_UTF8_SUBSTITUTE to replace broken characters.

How do I check whether a string is valid JSON?

In PHP 8.3 and later, json_validate($text) returns true or false without building the decoded data, which saves memory for large inputs. In earlier versions, decode it with JSON_THROW_ON_ERROR inside a try block and catch JsonException.

What is the difference between JSON and serialize()?

JSON is a language-independent format that JavaScript, Python and every other language can read. serialize() produces a PHP-specific format that can recreate PHP objects, and unserialize() on untrusted data is a security risk. Use JSON for APIs, files and anything stored long term.

Why does a decimal look slightly wrong in my JSON?

Floats are stored in binary, so 0.1 + 0.2 encodes as 0.30000000000000004. Round values before encoding, round($total, 2), or send money as whole cents or as strings formatted with number_format, so the receiving program shows the exact amount.

PHP JSON Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the code that turns $data into JSON text.

echo ($data);
Predict the outputeasy

What does this output?

echo json_encode(['a' => 1, 'b' => [2, 3]]);
Predict the outputmedium

What does this output?

$d = json_decode('{"user":{"name":"Leo","age":15}}', true);
echo $d['user']['age'] + 1;
Multiple choicemedium

Which header should a PHP script send when it returns JSON?

Multiple choicehard

How can you make json_decode throw an exception on invalid input?

PHP JSON Quiz

5 questions to check what you learned.

  1. What is JSON mainly used for?

    • Styling web pages
    • Exchanging data between programs and services
    • Storing passwords
    • Compressing images
  2. What does json_decode return for invalid JSON by default?

    • An empty array
    • false
    • An exception
    • null
  3. What does JSON_PRETTY_PRINT do?

    • Removes spaces
    • Adds line breaks and indentation so JSON is easy to read
    • Sorts the keys
    • Converts numbers to strings
  4. What PHP type does json_decode($json, true) use for JSON objects?

    • stdClass objects
    • Strings
    • Indexed arrays only
    • Associative arrays
  5. Why might json_encode(array_filter($list)) produce an object instead of an array?

    • array_filter returns a string
    • json_encode always returns objects
    • array_filter keeps original keys, so they're no longer 0, 1, 2 in order
    • Filtered arrays can't be encoded