100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
PHP

Working with JSON in PHP

Learn how to encode PHP data to JSON and decode JSON back into PHP values using json_encode and json_decode, plus common pitfalls and error handling.

Databases & PersistenceBeginner8 min readJul 9, 2026
Analogies

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

Was this page helpful?

Topics covered

#PHP#PHPProgrammingStudyNotes#Programming#WorkingWithJSONInPHP#JSON#Encoding#Data#Decoding#StudyNotes#SkillVeris