JSON (JavaScript Object Notation) é um formato leve de intercâmbio de dados, amplamente utilizado em APIs, configurações e comunicação entre sistemas. No PHP, o suporte a JSON é nativo, com funções simples e poderosas que permitem converter dados entre estruturas PHP e strings JSON. Nesta aula, vamos explorar as funções json_encode e json_decode, as flags que controlam o comportamento da serialização, as diferenças entre objetos e arrays associativos, e como lidar com erros de forma robusta.

Dominar JSON é essencial para qualquer desenvolvedor PHP moderno, pois é o formato padrão em serviços REST, integrações com JavaScript e armazenamento de dados estruturados. Vamos começar com o básico e avançar para técnicas mais refinadas, garantindo que você consiga usar JSON com confiança em seus projetos.

json_encode e json_decode

As duas funções principais para trabalhar com JSON em PHP são json_encode e json_decode. json_encode converte um valor PHP (arrays, objetos, strings, números, booleanos, null) em uma string JSON. json_decode faz o inverso: converte uma string JSON em um valor PHP.

Exemplo básico de json_encode:

<?php
$dados = [
    'nome' => 'Maria',
    'idade' => 30,
    'email' => 'maria@example.com'
];

$json = json_encode($dados);
echo $json; // {"nome":"Maria","idade":30,"email":"maria@example.com"}
?>

E o correspondente json_decode:

<?php
$json = '{"nome":"Maria","idade":30,"email":"maria@example.com"}';

$dados = json_decode($json);
var_dump($dados);
// object(stdClass)#1 (3) { ["nome"]=> string(5) "Maria" ["idade"]=> int(30) ["email"]=> string(17) "maria@example.com" }
?>

Note que, por padrão, json_decode retorna objetos da classe stdClass quando o JSON contém objetos. Se você passar true como segundo argumento, ele retorna arrays associativos:

<?php
$dados = json_decode($json, true);
var_dump($dados);
// array(3) { ["nome"]=> string(5) "Maria" ["idade"]=> int(30) ["email"]=> string(17) "maria@example.com" }
?>

Ambas as funções são essenciais para comunicação com APIs, armazenamento de dados em arquivos JSON e muito mais.

Flags

As funções json_encode e json_decode aceitam flags que alteram seu comportamento. Essas flags são constantes predefinidas do PHP, como JSON_PRETTY_PRINT, JSON_UNESCAPED_UNICODE, JSON_UNESCAPED_SLASHES, JSON_THROW_ON_ERROR, entre outras. Elas podem ser combinadas usando o operador pipe (|).

json_encode flags:

  • JSON_PRETTY_PRINT: formata a saída com espaços e quebras de linha, facilitando a leitura.
  • JSON_UNESCAPED_UNICODE: não escapa caracteres Unicode (ex.: acentos), produzindo JSON com caracteres legíveis.
  • JSON_UNESCAPED_SLASHES: não escapa barras (/), útil para URLs.
  • JSON_NUMERIC_CHECK: converte strings numéricas em números.
  • JSON_FORCE_OBJECT: força a saída como objeto, mesmo para arrays indexados.
  • JSON_THROW_ON_ERROR: lança uma exceção JsonException em caso de erro (disponível a partir do PHP 7.3).

Exemplo com JSON_PRETTY_PRINT e JSON_UNESCAPED_UNICODE:

<?php
$dados = [
    'nome' => 'João',
    'cidade' => 'São Paulo'
];

echo json_encode($dados, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>

Saída:

{
    "nome": "João",
    "cidade": "São Paulo"
}

json_decode flags:

  • JSON_OBJECT_AS_ARRAY: equivale a passar true como segundo argumento; retorna arrays associativos.
  • JSON_BIGINT_AS_STRING: converte inteiros grandes em strings para evitar perda de precisão.
  • JSON_THROW_ON_ERROR: lança exceção em caso de erro.

Exemplo com JSON_BIGINT_AS_STRING:

<?php
$json = '{"id": 12345678901234567890}';
$obj = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
echo $obj->id; // 12345678901234567890 (como string)
?>

As flags permitem ajustar o comportamento às necessidades específicas, seja para legibilidade, compatibilidade ou desempenho.

Objetos vs arrays associativos

No PHP, arrays associativos e objetos são estruturas de dados diferentes, e isso se reflete na serialização JSON. Arrays associativos viram objetos JSON, enquanto arrays indexados viram arrays JSON. Objetos PHP (instâncias de classes) também viram objetos JSON, com suas propriedades.

Exemplo: array associativo vira objeto JSON:

<?php
$array = ['a' => 1, 'b' => 2];
echo json_encode($array); // {"a":1,"b":2}
?>

Array indexado vira array JSON:

<?php
$array = [1, 2, 3];
echo json_encode($array); // [1,2,3]
?>

Objeto PHP:

<?php
class Pessoa {
    public $nome = 'Carlos';
    public $idade = 25;
}
$p = new Pessoa();
echo json_encode($p); // {"nome":"Carlos","idade":25}
?>

Ao decodificar, você pode escolher entre objeto ou array associativo. Objetos são úteis quando você quer acessar propriedades com sintaxe de objeto ($obj->prop), enquanto arrays associativos são mais convenientes para funções de array. A escolha depende do contexto.

Uma diferença importante: se você decodificar um objeto JSON como array associativo, as chaves podem ser acessadas como índices. Mas cuidado com chaves que são números: elas podem ser convertidas para inteiros em arrays, o que pode causar confusão. Nesse caso, usar objetos é mais seguro.

<?php
$json = '{"0": "zero", "1": "um"}';
$arr = json_decode($json, true);
var_dump($arr); // array(2) { [0]=> string(4) "zero" [1]=> string(3) "um" }
?>

Isso pode ser um problema se você esperava chaves como strings. Para evitar isso, use JSON_OBJECT_AS_ARRAY com cuidado ou prefira objetos.

Tratamento de erros

Erros podem ocorrer ao codificar ou decodificar JSON: dados inválidos, profundidade máxima excedida, caracteres inválidos, etc. O PHP fornece a função json_last_error() que retorna o código do último erro, e json_last_error_msg() que retorna a mensagem. A partir do PHP 7.3, a flag JSON_THROW_ON_ERROR permite lançar uma exceção JsonException, facilitando o tratamento com try/catch.

Exemplo com json_last_error:

<?php
$json = '{"nome": "Maria"';
$dados = json_decode($json);
if (json_last_error() !== JSON_ERROR_NONE) {
    echo 'Erro: ' . json_last_error_msg();
}
?>

Com JSON_THROW_ON_ERROR, o código fica mais limpo:

<?php
try {
    $dados = json_decode('{"nome": "Maria"', true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    echo 'Erro: ' . $e->getMessage();
}
?>

Também é importante verificar o erro em json_encode. Por exemplo, se houver strings inválidas em UTF-8, a codificação pode falhar. Use JSON_INVALID_UTF8_SUBSTITUTE ou JSON_INVALID_UTF8_IGNORE para lidar com isso.

<?php
$dados = ['nome' => "\xB1\x31"]; // caractere inválido
$json = json_encode($dados, JSON_INVALID_UTF8_SUBSTITUTE);
echo $json; // {"nome":"�1"}
?>

Adotar JSON_THROW_ON_ERROR é uma boa prática em código moderno, pois evita esquecimentos de verificação e torna o fluxo de erro mais explícito.

Boas práticas e observações finais

  • Sempre valide a entrada JSON antes de usar, especialmente se ela vier de fontes externas.
  • Use JSON_UNESCAPED_UNICODE ao gerar JSON para leitura humana, mas lembre-se de que isso pode aumentar o tamanho da string.
  • Prefira JSON_THROW_ON_ERROR para um tratamento de erros consistente.
  • Para arrays com chaves numéricas, esteja ciente do comportamento de conversão ao decodificar como array associativo.
  • Ao trabalhar com APIs, defina o cabeçalho Content-Type: application/json ao enviar respostas.
  • Considere usar JSON_PRETTY_PRINT apenas em ambientes de desenvolvimento, pois adiciona espaços desnecessários em produção.

Exercícios

  1. Escreva um script PHP que converte um array associativo em uma string JSON e exiba o resultado.
  2. ✓ Resposta:
    <?php
    $dados = ['nome' => 'Ana', 'idade' => 28];
    echo json_encode($dados);
    ?>
  3. Decodifique a string JSON {"produto":"Notebook","preco":2999.90} como array associativo e imprima o preço.
  4. ✓ Resposta:
    <?php
    $json = '{"produto":"Notebook","preco":2999.90}';
    $dados = json_decode($json, true);
    echo $dados['preco']; // 2999.9
    ?>
  5. Use json_encode com a flag JSON_PRETTY_PRINT para formatar um array aninhado e exiba a saída.
  6. ✓ Resposta:
    <?php
    $dados = [
        'usuario' => [
            'nome' => 'João',
            'email' => 'joao@example.com'
        ]
    ];
    echo json_encode($dados, JSON_PRETTY_PRINT);
    ?>
  7. Crie uma classe PHP com propriedades públicas e serialize-a para JSON. Depois, decodifique o JSON e acesse uma propriedade.
  8. ✓ Resposta:
    <?php
    class Carro {
        public $marca = 'Toyota';
        public $ano = 2020;
    }
    $carro = new Carro();
    $json = json_encode($carro);
    $obj = json_decode($json);
    echo $obj->marca; // Toyota
    ?>
  9. Escreva um código que tenta decodificar um JSON inválido usando JSON_THROW_ON_ERROR e captura a exceção, exibindo a mensagem de erro.
  10. ✓ Resposta:
    <?php
    try {
        $json = '{"nome": "Maria"';
        $dados = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        echo 'Erro: ' . $e->getMessage();
    }
    ?>

Referências