1. php
  2. /references
  3. /json-functions

PHP JSON Functions

Introduction to PHP JSON Functions

PHP provides built-in functions for working with JSON (JavaScript Object Notation), a lightweight data interchange format commonly used in web APIs and modern applications.

Basic JSON Operations

Encoding PHP Data to JSON

<?php
// json_encode() - Convert PHP data to JSON string

// Arrays
$array = ['apple', 'banana', 'cherry'];
echo json_encode($array); // ["apple","banana","cherry"]

// Associative arrays become JSON objects
$assoc = ['name' => 'John', 'age' => 30, 'city' => 'New York'];
echo json_encode($assoc); // {"name":"John","age":30,"city":"New York"}

// Nested structures
$data = [
    'user' => [
        'name' => 'John Doe',
        'email' => '[email protected]',
        'preferences' => [
            'theme' => 'dark',
            'notifications' => true
        ]
    ],
    'posts' => [
        ['title' => 'First Post', 'likes' => 10],
        ['title' => 'Second Post', 'likes' => 5]
    ]
];
echo json_encode($data);
?>

Decoding JSON to PHP Data

<?php
// json_decode() - Convert JSON string to PHP data

$json = '{"name":"John","age":30,"city":"New York"}';

// Decode to associative array (default)
$array = json_decode($json, true);
print_r($array);
// Array ( [name] => John [age] => 30 [city] => New York )

// Decode to object
$object = json_decode($json);
echo $object->name; // John
echo $object->age;  // 30

// Complex JSON
$complexJson = '{
    "users": [
        {"id": 1, "name": "John", "active": true},
        {"id": 2, "name": "Jane", "active": false}
    ],
    "total": 2
}';

$data = json_decode($complexJson, true);
foreach ($data['users'] as $user) {
    echo "User: " . $user['name'] . " (ID: " . $user['id'] . ")\n";
}
?>

JSON Encoding Options

Common Encoding Flags

<?php
$data = [
    'name' => 'John Doe',
    'age' => 30,
    'scores' => [85, 90, 78],
    'address' => [
        'street' => '123 Main St',
        'city' => 'New York'
    ]
];

// Pretty print JSON (formatted)
echo json_encode($data, JSON_PRETTY_PRINT);
/*
{
    "name": "John Doe",
    "age": 30,
    "scores": [
        85,
        90,
        78
    ],
    "address": {
        "street": "123 Main St",
        "city": "New York"
    }
}
*/

// Unescaped Unicode
$unicode = ['message' => 'Hello 世界'];
echo json_encode($unicode, JSON_UNESCAPED_UNICODE);
// {"message":"Hello 世界"}

// Unescaped slashes
$url = ['website' => 'https://example.com/path'];
echo json_encode($url, JSON_UNESCAPED_SLASHES);
// {"website":"https://example.com/path"}

// Force object output for empty arrays
$empty = [];
echo json_encode($empty, JSON_FORCE_OBJECT);
// {}

// Combine multiple flags
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
?>

Handling Special Values

<?php
// Numeric strings
$data = ['id' => '123', 'score' => '95.5'];
echo json_encode($data, JSON_NUMERIC_CHECK);
// {"id":123,"score":95.5}

// HTML entities
$html = ['content' => '<script>alert("hello")</script>'];
echo json_encode($html, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);

// Preserve zero fraction
$numbers = ['price' => 10.00, 'tax' => 1.50];
echo json_encode($numbers, JSON_PRESERVE_ZERO_FRACTION);
// {"price":10.0,"tax":1.5}

// Invalid UTF-8 handling
$invalid = ['text' => "Invalid UTF-8: \x80\x81"];
echo json_encode($invalid, JSON_INVALID_UTF8_SUBSTITUTE);
?>

JSON Decoding Options

Decoding Configuration

<?php
$json = '{"name":"John","age":30,"height":5.8,"active":true,"address":null}';

// Maximum depth (default is 512)
$data = json_decode($json, true, 10);

// Decode as objects with specific class
class User {
    public $name;
    public $age;
    public $height;
    public $active;
    public $address;
}

// Decode large integers as strings
$bigNumber = '{"bigint": 9223372036854775808}';
$result = json_decode($bigNumber, true, 512, JSON_BIGINT_AS_STRING);
echo $result['bigint']; // "9223372036854775808"

// Throw exceptions on error (PHP 7.3+)
try {
    $invalid = '{"invalid": json}';
    $result = json_decode($invalid, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    echo "JSON Error: " . $e->getMessage();
}
?>

Error Handling

Traditional Error Handling

<?php
function safeJsonDecode($json, $assoc = true) {
    $data = json_decode($json, $assoc);
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new InvalidArgumentException('JSON decode error: ' . json_last_error_msg());
    }
    
    return $data;
}

function safeJsonEncode($data, $options = 0) {
    $json = json_encode($data, $options);
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new RuntimeException('JSON encode error: ' . json_last_error_msg());
    }
    
    return $json;
}

// Usage
try {
    $invalid = '{"name": "John", "age":}'; // Invalid JSON
    $data = safeJsonDecode($invalid);
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

// Check specific error types
$json = '{"name": "John"}';
$data = json_decode($json);

switch (json_last_error()) {
    case JSON_ERROR_NONE:
        echo 'No errors';
        break;
    case JSON_ERROR_DEPTH:
        echo 'Maximum stack depth exceeded';
        break;
    case JSON_ERROR_STATE_MISMATCH:
        echo 'Underflow or the modes mismatch';
        break;
    case JSON_ERROR_CTRL_CHAR:
        echo 'Unexpected control character found';
        break;
    case JSON_ERROR_SYNTAX:
        echo 'Syntax error, malformed JSON';
        break;
    case JSON_ERROR_UTF8:
        echo 'Malformed UTF-8 characters';
        break;
    default:
        echo 'Unknown error';
        break;
}
?>

Modern Error Handling (PHP 7.3+)

<?php
// Using JSON_THROW_ON_ERROR flag
function modernJsonDecode($json, $assoc = true) {
    try {
        return json_decode($json, $assoc, 512, JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        throw new InvalidArgumentException("Failed to decode JSON: " . $e->getMessage(), 0, $e);
    }
}

function modernJsonEncode($data, $options = 0) {
    try {
        return json_encode($data, $options | JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        throw new RuntimeException("Failed to encode JSON: " . $e->getMessage(), 0, $e);
    }
}

// Usage
try {
    $data = modernJsonDecode('{"invalid": json}');
} catch (InvalidArgumentException $e) {
    echo "Decode error: " . $e->getMessage();
}

try {
    $invalid = "\xB1\x31"; // Invalid UTF-8
    $json = modernJsonEncode(['text' => $invalid]);
} catch (RuntimeException $e) {
    echo "Encode error: " . $e->getMessage();
}
?>

Working with JSON APIs

HTTP API Requests

<?php
class JsonApiClient {
    private $baseUrl;
    private $headers;
    
    public function __construct($baseUrl) {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->headers = [
            'Content-Type: application/json',
            'Accept: application/json'
        ];
    }
    
    public function get($endpoint) {
        $url = $this->baseUrl . '/' . ltrim($endpoint, '/');
        
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'header' => implode("\r\n", $this->headers)
            ]
        ]);
        
        $response = file_get_contents($url, false, $context);
        
        if ($response === false) {
            throw new RuntimeException('Failed to fetch data from API');
        }
        
        return $this->parseResponse($response);
    }
    
    public function post($endpoint, $data) {
        $url = $this->baseUrl . '/' . ltrim($endpoint, '/');
        $jsonData = json_encode($data, JSON_THROW_ON_ERROR);
        
        $context = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => implode("\r\n", $this->headers),
                'content' => $jsonData
            ]
        ]);
        
        $response = file_get_contents($url, false, $context);
        
        if ($response === false) {
            throw new RuntimeException('Failed to send data to API');
        }
        
        return $this->parseResponse($response);
    }
    
    private function parseResponse($response) {
        try {
            return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            throw new RuntimeException('Invalid JSON response: ' . $e->getMessage());
        }
    }
}

// Usage
$client = new JsonApiClient('https://api.example.com');

try {
    $users = $client->get('/users');
    foreach ($users as $user) {
        echo "User: " . $user['name'] . "\n";
    }
    
    $newUser = $client->post('/users', [
        'name' => 'John Doe',
        'email' => '[email protected]'
    ]);
    echo "Created user with ID: " . $newUser['id'];
    
} catch (Exception $e) {
    echo "API Error: " . $e->getMessage();
}
?>

Response Formatting

<?php
class JsonResponse {
    public static function success($data = null, $message = 'Success', $statusCode = 200) {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        
        $response = [
            'success' => true,
            'message' => $message
        ];
        
        if ($data !== null) {
            $response['data'] = $data;
        }
        
        echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    public static function error($message, $statusCode = 400, $errors = null) {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        
        $response = [
            'success' => false,
            'message' => $message
        ];
        
        if ($errors !== null) {
            $response['errors'] = $errors;
        }
        
        echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    public static function paginated($data, $page, $perPage, $total) {
        $totalPages = ceil($total / $perPage);
        
        self::success([
            'items' => $data,
            'pagination' => [
                'current_page' => $page,
                'per_page' => $perPage,
                'total' => $total,
                'total_pages' => $totalPages,
                'has_next' => $page < $totalPages,
                'has_prev' => $page > 1
            ]
        ]);
    }
}

// Usage in API endpoints
try {
    $users = getUsersFromDatabase();
    JsonResponse::success($users, 'Users retrieved successfully');
} catch (Exception $e) {
    JsonResponse::error('Failed to retrieve users', 500);
}
?>

Advanced JSON Operations

JSON Schema Validation

<?php
class JsonValidator {
    public static function validateUser($data) {
        $errors = [];
        
        // Required fields
        $required = ['name', 'email'];
        foreach ($required as $field) {
            if (!isset($data[$field]) || empty($data[$field])) {
                $errors[] = "Field '{$field}' is required";
            }
        }
        
        // Email validation
        if (isset($data['email']) && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            $errors[] = "Invalid email format";
        }
        
        // Age validation
        if (isset($data['age']) && (!is_numeric($data['age']) || $data['age'] < 0 || $data['age'] > 150)) {
            $errors[] = "Age must be a number between 0 and 150";
        }
        
        return $errors;
    }
    
    public static function validateApiRequest($json) {
        try {
            $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            return ['Invalid JSON format: ' . $e->getMessage()];
        }
        
        return self::validateUser($data);
    }
}

// Usage
$requestBody = file_get_contents('php://input');
$errors = JsonValidator::validateApiRequest($requestBody);

if (!empty($errors)) {
    JsonResponse::error('Validation failed', 400, $errors);
}
?>

JSON Streaming for Large Data

<?php
class JsonStreamer {
    private $handle;
    
    public function __construct($filename) {
        $this->handle = fopen($filename, 'w');
        if (!$this->handle) {
            throw new RuntimeException("Cannot open file for writing: {$filename}");
        }
    }
    
    public function startArray() {
        fwrite($this->handle, '[');
    }
    
    public function writeItem($data, $isFirst = false) {
        if (!$isFirst) {
            fwrite($this->handle, ',');
        }
        fwrite($this->handle, json_encode($data));
    }
    
    public function endArray() {
        fwrite($this->handle, ']');
    }
    
    public function close() {
        if ($this->handle) {
            fclose($this->handle);
            $this->handle = null;
        }
    }
    
    public function __destruct() {
        $this->close();
    }
}

// Stream large dataset to JSON file
$streamer = new JsonStreamer('large_dataset.json');
$streamer->startArray();

$users = getUsersFromDatabase(); // Large dataset
foreach ($users as $index => $user) {
    $streamer->writeItem($user, $index === 0);
}

$streamer->endArray();
$streamer->close();

// Read large JSON file in chunks
function readJsonStream($filename, $callback) {
    $handle = fopen($filename, 'r');
    if (!$handle) {
        throw new RuntimeException("Cannot open file: {$filename}");
    }
    
    $buffer = '';
    $depth = 0;
    $inString = false;
    $escaped = false;
    
    while (!feof($handle)) {
        $chunk = fread($handle, 8192);
        $buffer .= $chunk;
        
        // Simple JSON parsing (for demonstration)
        // In production, use a proper streaming JSON parser
        $objects = explode('},{', $buffer);
        
        foreach ($objects as $index => $object) {
            if ($index === count($objects) - 1 && !feof($handle)) {
                $buffer = $object;
                break;
            }
            
            $object = '{' . trim($object, '[]{}') . '}';
            
            try {
                $data = json_decode($object, true, 512, JSON_THROW_ON_ERROR);
                $callback($data);
            } catch (JsonException $e) {
                // Handle parsing errors
            }
        }
    }
    
    fclose($handle);
}
?>

Performance Considerations

Optimizing JSON Operations

<?php
class JsonPerformance {
    public static function benchmarkEncoding($data, $iterations = 1000) {
        $start = microtime(true);
        
        for ($i = 0; $i < $iterations; $i++) {
            json_encode($data);
        }
        
        $end = microtime(true);
        return ($end - $start) * 1000; // Return milliseconds
    }
    
    public static function optimizeForSpeed($data) {
        // Use minimal flags for maximum speed
        return json_encode($data, JSON_UNESCAPED_SLASHES);
    }
    
    public static function optimizeForSize($data) {
        // Remove unnecessary whitespace
        return json_encode($data);
    }
    
    public static function optimizeForReadability($data) {
        // Use pretty print for debugging
        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }
    
    public static function memoryEfficientEncode($largeArray) {
        // For very large arrays, consider streaming
        $tempFile = tempnam(sys_get_temp_dir(), 'json_');
        $handle = fopen($tempFile, 'w');
        
        fwrite($handle, '[');
        
        foreach ($largeArray as $index => $item) {
            if ($index > 0) {
                fwrite($handle, ',');
            }
            fwrite($handle, json_encode($item));
        }
        
        fwrite($handle, ']');
        fclose($handle);
        
        $result = file_get_contents($tempFile);
        unlink($tempFile);
        
        return $result;
    }
}

// Example usage
$data = ['user' => 'John', 'scores' => range(1, 100)];

echo "Speed optimized: " . JsonPerformance::optimizeForSpeed($data) . "\n";
echo "Size optimized: " . JsonPerformance::optimizeForSize($data) . "\n";
echo "Readable: " . JsonPerformance::optimizeForReadability($data) . "\n";

$time = JsonPerformance::benchmarkEncoding($data);
echo "Encoding time: {$time} ms\n";
?>

Best Practices

Security Considerations

<?php
class SecureJsonHandler {
    private $maxDepth;
    private $maxSize;
    
    public function __construct($maxDepth = 512, $maxSize = 1048576) { // 1MB default
        $this->maxDepth = $maxDepth;
        $this->maxSize = $maxSize;
    }
    
    public function safeDecode($json) {
        // Check size limit
        if (strlen($json) > $this->maxSize) {
            throw new InvalidArgumentException('JSON string too large');
        }
        
        // Validate JSON structure
        if (!$this->isValidJsonStructure($json)) {
            throw new InvalidArgumentException('Invalid JSON structure');
        }
        
        try {
            return json_decode($json, true, $this->maxDepth, JSON_THROW_ON_ERROR);
        } catch (JsonException $e) {
            throw new InvalidArgumentException('JSON decode error: ' . $e->getMessage());
        }
    }
    
    public function safeEncode($data) {
        try {
            $json = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
            
            // Check resulting size
            if (strlen($json) > $this->maxSize) {
                throw new RuntimeException('Encoded JSON too large');
            }
            
            return $json;
        } catch (JsonException $e) {
            throw new RuntimeException('JSON encode error: ' . $e->getMessage());
        }
    }
    
    private function isValidJsonStructure($json) {
        // Basic structure validation
        $trimmed = trim($json);
        return (
            (str_starts_with($trimmed, '{') && str_ends_with($trimmed, '}')) ||
            (str_starts_with($trimmed, '[') && str_ends_with($trimmed, ']'))
        );
    }
    
    public function sanitizeInput($data) {
        if (is_array($data)) {
            return array_map([$this, 'sanitizeInput'], $data);
        }
        
        if (is_string($data)) {
            // Remove potential XSS characters
            return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
        }
        
        return $data;
    }
}

// Usage
$handler = new SecureJsonHandler();

try {
    $data = $handler->safeDecode($userInput);
    $sanitized = $handler->sanitizeInput($data);
    $response = $handler->safeEncode($sanitized);
} catch (Exception $e) {
    error_log('JSON processing error: ' . $e->getMessage());
    JsonResponse::error('Invalid data format');
}
?>

PHP's JSON functions provide robust tools for handling JSON data in modern web applications, with proper error handling and security considerations being essential for production use.