Working with JSON in PHP
JSON (JavaScript Object Notation) is the de facto data interchange format for web APIs, and PHP has built-in functions for converting between PHP values and JSON text: json_encode() turns PHP arrays, objects, and scalars into a JSON string, while json_decode() parses a JSON string back into PHP data. Because nearly every modern PHP application either serves or consumes a JSON API, understanding these functions' options and edge cases is essential.
Cricket analogy: json_encode() turning a PHP array of match stats into JSON text for a scoreboard API, and json_decode() parsing a JSON feed from another cricket API back into PHP data, is like a scorer translating handwritten notes into the standardized digital format broadcasters share worldwide.
Encoding PHP data to JSON
json_encode() maps PHP types fairly directly: associative arrays and objects become JSON objects, sequential (list-like) arrays become JSON arrays, strings become JSON strings, and null, true, and false map to their JSON equivalents. Public properties of objects — including ones implementing the JsonSerializable interface — are included automatically; JsonSerializable lets a class define exactly what jsonSerialize() should return, giving full control over its JSON representation regardless of its actual property visibility.
Cricket analogy: json_encode() mapping an associative array of a player's stats into a JSON object, and a sequential array of match scores into a JSON array, is straightforward; a Player class implementing JsonSerializable lets it define exactly which fields (say, only public career stats, not private medical notes) appear in the JSON output.
<?php
declare(strict_types=1);
final class Product implements JsonSerializable
{
public function __construct(
public readonly int $id,
public readonly string $name,
public readonly float $price,
private readonly string $internalSku,
) {}
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
];
}
}
$products = [
new Product(1, 'Keyboard', 49.99, 'SKU-001'),
new Product(2, 'Mouse', 19.50, 'SKU-002'),
];
$json = json_encode(
['products' => $products, 'count' => count($products)],
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
);
echo $json;
// Decoding back, as associative arrays
$decoded = json_decode($json, associative: true, flags: JSON_THROW_ON_ERROR);
echo $decoded['products'][0]['name']; // "Keyboard"Decoding JSON and the associative flag
json_decode() by default returns stdClass objects for JSON objects; passing true as the second argument (or associative: true as a named argument) instead returns associative arrays, which many developers prefer for simpler array-style access. The choice affects how you subsequently access the data — $decoded->name versus $decoded['name'] — so it should be applied consistently across a codebase to avoid confusion.
Cricket analogy: json_decode() of a match-stats JSON response returning a stdClass by default means accessing $decoded->runs, while passing true returns an associative array accessed as $decoded['runs']; a scoring app should pick one style consistently, the way a scorer sticks to one notation system throughout a match.
By default, json_decode() returns null both for invalid JSON and for JSON that legitimately decodes to the value null, making error detection ambiguous if you only check the return value. Always pass the JSON_THROW_ON_ERROR flag (or check json_last_error() explicitly) so malformed JSON throws a JsonException instead of silently returning null.
Common encoding flags
Beyond JSON_THROW_ON_ERROR, useful flags include JSON_PRETTY_PRINT for human-readable indented output, JSON_UNESCAPED_SLASHES to stop forward slashes from being escaped as \/, and JSON_UNESCAPED_UNICODE to output multi-byte UTF-8 characters directly rather than as \uXXXX escape sequences. Flags can be combined with the bitwise OR operator, as shown in the example above.
Cricket analogy: JSON_PRETTY_PRINT formatting a match-stats export with clean indentation is like a scorecard printed for a match programme instead of a cramped ledger; JSON_UNESCAPED_UNICODE keeping a player's name like 'Müller' intact rather than as \u00fc escapes preserves it correctly for international broadcasts, combined via bitwise OR.
A sequential PHP array like [10, 20, 30] encodes to a JSON array [10,20,30], but an array with gaps or non-sequential integer keys, like [0 => 'a', 2 => 'b'], encodes to a JSON object {"0":"a","2":"b"} instead — PHP decides this based on whether the keys form a contiguous zero-indexed sequence.
- json_encode() converts PHP values to JSON text; json_decode() parses JSON text back into PHP values.
- Classes implementing JsonSerializable control their own JSON shape via jsonSerialize(), independent of property visibility.
- json_decode()'s second argument (or associative: true) controls whether objects decode to stdClass or associative arrays.
- Always use JSON_THROW_ON_ERROR to catch malformed JSON as an exception instead of silently getting null.
- JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, and JSON_UNESCAPED_UNICODE are commonly combined encoding flags.
- Whether a PHP array encodes as a JSON array or object depends on whether its keys are a contiguous zero-based sequence.
Practice what you learned
1. What does implementing JsonSerializable on a class allow you to control?
2. By default, what type does json_decode() return for a JSON object?
3. Why is checking only 'if (json_decode($str) === null)' an unreliable way to detect invalid JSON?
4. What determines whether json_encode() outputs a PHP array as a JSON array versus a JSON object?
5. What does the JSON_UNESCAPED_UNICODE flag do in json_encode()?
Was this page helpful?
You May Also Like
Superglobals and Request Data
Explore PHP's built-in superglobal arrays that expose incoming HTTP request data, server information, and environment variables to every scope without needing to be passed or imported.
Type Declarations and Strict Types
PHP supports optional scalar and object type declarations on parameters, return values, and properties, with strict_types controlling how aggressively the engine coerces mismatched values.
Classes and Objects
Explore PHP's object-oriented foundations: declaring classes, constructing objects, typed properties, visibility, and constructor promotion.
Exceptions and Error Handling
Learn how PHP represents runtime failures as throwable objects, how try/catch/finally blocks control the flow around them, and how to design a clean exception hierarchy for your application.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics