PHP JSON

Encode and decode JSON, control encoding options, handle errors with JsonException, customize objects via JsonSerializable, and use JSON for REST APIs.

Intermediate 7 min read 8 examples

json_encode

PHP
<?php
$user = ["name" => "Ruban", "age" => 30, "admin" => true];

echo json_encode($user);
// {"name":"Ruban","age":30,"admin":true}

// Pretty + unicode-friendly + no escaped slashes
echo json_encode($user,
    JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

// Empty array -> []  (object pass-through preserves stdClass as {})
echo json_encode([]);           // "[]"
echo json_encode(new stdClass); // "{}"

// Force an array to be encoded as object
echo json_encode($map, JSON_FORCE_OBJECT);

json_decode

PHP
<?php
$json = '{"name":"Ruban","age":30,"tags":["php","web"]}';

// As objects (default)
$obj = json_decode($json);
echo $obj->name;                // "Ruban"
echo $obj->tags[0];             // "php"

// As associative array (recommended for most cases)
$arr = json_decode($json, associative: true);
echo $arr["name"];
echo $arr["tags"][0];

// Limit recursion depth
$x = json_decode($json, true, depth: 32);

// Decode large integers as strings (no float precision loss)
$x = json_decode($json, true, flags: JSON_BIGINT_AS_STRING);

Error Handling

PHP
<?php
// Modern - throw on error (PHP 7.3+)
try {
    $data = json_decode($input, true, flags: JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    http_response_code(400);
    echo "Invalid JSON: " . $e->getMessage();
}

// Old-style (still works)
$data = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    die("JSON error: " . json_last_error_msg());
}

JsonSerializable Interface

Control exactly how your object is converted to JSON:

PHP
<?php
class User implements JsonSerializable {
    public function __construct(
        public int $id,
        public string $name,
        private string $passwordHash,    // private - keep it out of JSON
    ) {}

    public function jsonSerialize(): array {
        return [
            "id"   => $this->id,
            "name" => $this->name,
            // passwordHash deliberately omitted
        ];
    }
}

$user = new User(1, "Ruban", "secret-hash");
echo json_encode($user);    // {"id":1,"name":"Ruban"}

Unicode & Escaping

PHP
<?php
$data = ["city" => "São Paulo", "url" => "https://example.com/path"];

echo json_encode($data);
// {"city":"São Paulo","url":"https:\/\/example.com\/path"}

echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// {"city":"São Paulo","url":"https://example.com/path"}

// For HTML-safe inline JSON (e.g., in a <script> tag)
echo json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_QUOT);

Building a JSON API Endpoint

PHPapi/users.php
<?php
header("Content-Type: application/json; charset=utf-8");

try {
    $method = $_SERVER["REQUEST_METHOD"];

    if ($method === "POST") {
        $input = json_decode(
            file_get_contents("php://input"),
            true,
            flags: JSON_THROW_ON_ERROR
        );

        // validate $input ...
        $user = createUser($input);
        http_response_code(201);
        echo json_encode($user);
    } elseif ($method === "GET") {
        $users = getAllUsers();
        echo json_encode([
            "data" => $users,
            "count" => count($users),
        ]);
    } else {
        http_response_code(405);
        echo json_encode(["error" => "Method not allowed"]);
    }
} catch (JsonException $e) {
    http_response_code(400);
    echo json_encode(["error" => "Invalid JSON"]);
} catch (Throwable $e) {
    error_log($e);
    http_response_code(500);
    echo json_encode(["error" => "Internal error"]);
}

Consuming a JSON API

PHP
<?php
// Simple GET with file_get_contents
$context = stream_context_create([
    "http" => ["header" => "Accept: application/json"],
]);
$body = file_get_contents("https://api.example.com/users/42", false, $context);
$user = json_decode($body, true);

// POST with cURL (more control, better for production)
$ch = curl_init("https://api.example.com/users");
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode(["name" => "Ruban"]),
    CURLOPT_HTTPHEADER     => [
        "Content-Type: application/json",
        "Authorization: Bearer " . $token,
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 10,
]);
$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 200 && $status < 300) {
    $created = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
}

Next Steps

Frequently Asked Questions

Pass true as the second argument to get associative arrays - usually more convenient in PHP. Objects (stdClass) are slightly faster but harder to work with for unknown structures.

Pass JSON_THROW_ON_ERROR as the flags argument. PHP throws a JsonException on malformed input - much cleaner than checking json_last_error() after every call.

That's a valid escape but ugly. Pass JSON_UNESCAPED_UNICODE to json_encode() to keep multibyte characters as-is. Often combined with JSON_UNESCAPED_SLASHES and JSON_PRETTY_PRINT for human-readable output.

Probably a non-public property, a resource handle, a circular reference, or invalid UTF-8 in a string. Use JSON_THROW_ON_ERROR to get the exact reason as an exception message.

Almost. JSON requires double-quoted strings, no trailing commas, no comments, no functions. JavaScript object literal syntax is more permissive. JSON.parse() in JS and json_decode() in PHP follow the strict spec.