JSON (JavaScript Object Notation) adalah format pertukaran data de facto untuk API modern, berkas konfigurasi, dan penyimpanan ringan. Dibandingkan CSV, JSON mampu merepresentasikan struktur bertingkat: array di dalam object, object di dalam array, dan seterusnya. PHP hadir dengan ekstensi JSON yang selalu aktif berisi dua fungsi utama: json_decode() untuk mengubah JSON menjadi data PHP, dan json_encode() untuk sebaliknya. Pada Chapter ini kita akan mempelajari kedua arah konversi tersebut beserta validasi dan penanganan galatnya, sehingga data yang kita proses selalu dapat dipertanggungjawabkan.

Mengubah JSON menjadi Data PHP #

Fungsi json_decode() mengubah string JSON menjadi nilai PHP. Parameter keduanya, $associative, menentukan wujud hasilnya: false (bawaan) menghasilkan object stdClass, sedangkan true menghasilkan array asosiatif:

php
<?php
$json = '{"nama": "Budi", "umur": 28, "hobi": ["membaca", "coding"]}';

$obj = json_decode($json);
$arr = json_decode($json, true);

echo $obj->nama . "\n";
echo $arr["hobi"][1] . "\n";
echo get_debug_type($obj) . "\n";
echo get_debug_type($arr) . "\n";

Output yang Dihasilkan:

text
Budi
coding
stdClass
array

Mari kita telaah kode di atas:

  1. Baris 4: json_decode($json) tanpa parameter $associative menghasilkan object stdClass, sehingga nilainya diakses dengan sintaks panah: $obj->nama.
  2. Baris 5: json_decode($json, true) menghasilkan array asosiatif, sehingga nilainya diakses dengan kurung siku: $arr["hobi"][1].
  3. Baris 6-7: get_debug_type() mengonfirmasi wujud kedua hasil — stdClass dan array — dari eksekusi yang sama.

Array asosiatif umumnya lebih nyaman dipakai di kode prosedural karena bisa dimanipulasi dengan seluruh fungsi array seperti array_map() dan array_filter(). Selain kedua parameter tersebut, json_decode() juga menerima parameter $depth (kedalaman struktur maksimum, bawaan 512) dan $flags — kedalaman lebih dari 512 lapis akan membuat dekode gagal, sesuatu yang nyaris tidak pernah terjadi pada data wajar.

Mengubah Data PHP menjadi JSON #

Arah sebaliknya ditangani json_encode(). Perhatikan perilaku bawaannya terhadap karakter non-ASCII dan tanda garis miring:

php
<?php
$profil = [
    "nama" => "Siti Rahayu",
    "catatan" => "Harga sudah termasuk pajak — 10%",
    "website" => "https://example.com/siti",
];

echo json_encode($profil) . "\n";
echo json_encode($profil, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";

Output yang Dihasilkan:

text
{"nama":"Siti Rahayu","catatan":"Harga sudah termasuk pajak \u2014 10%","website":"https:\/\/example.com\/siti"}
{"nama":"Siti Rahayu","catatan":"Harga sudah termasuk pajak — 10%","website":"https://example.com/siti"}

Baris pertama hasil menunjukkan perilaku bawaan: karakter em dash diubah menjadi \u2014 dan garis miring menjadi \/. Hasil tersebut tetap JSON yang sah, tetapi lebih sulit dibaca manusia. Baris kedua menggunakan dua flag sekaligus dengan operator bitwise or (|): JSON_UNESCAPED_UNICODE mempertahankan karakter UTF-8 apa adanya dan JSON_UNESCAPED_SLASHES mempertahankan garis miring. Untuk data berbahasa Indonesia, kombinasi kedua flag ini sebaiknya menjadi kebiasaan default karena hasilnya lebih pendek dan lebih mudah dibaca.

Menyimpan JSON ke Berkas #

Pola umum pengolahan data adalah menyimpan hasil encode ke berkas, lalu membacanya kembali di eksekusi berikutnya. Flag JSON_PRETTY_PRINT membuat berkas mudah dibaca dan diperiksa manual:

php
<?php
$path = "/tmp/pengaturan.json";
$pengaturan = [
    "tema" => "gelap",
    "bahasa" => "id",
    "notifikasi" => ["email" => true, "sms" => false],
];

$encode = json_encode($pengaturan, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents($path, $encode);
echo $encode . "\n";

$dibaca = json_decode(file_get_contents($path), true);
echo "Tema: " . $dibaca["tema"] . "\n";
echo ($dibaca["notifikasi"]["email"] ? "Notifikasi email aktif" : "Notifikasi email nonaktif") . "\n";

Output yang Dihasilkan:

text
{
    "tema": "gelap",
    "bahasa": "id",
    "notifikasi": {
        "email": true,
        "sms": false
    }
}
Tema: gelap
Notifikasi email aktif

file_put_contents() menulis string JSON ke berkas, dan json_decode(file_get_contents($path), true) membacanya kembali menjadi array asosiatif. Tipe data ikut dipertahankan bolak-balik: boolean tetap true/false (bukan string "1"), integer tetap integer, dan null tetap null. Inilah keunggulan JSON dibanding CSV yang mengubah semua nilai menjadi string.

Memvalidasi JSON dengan json_validate #

Sebelum PHP 8.3, satu-satunya cara memeriksa keabsahan JSON adalah mencoba mendekodenya. Sejak PHP 8.3 tersedia json_validate() yang hanya memeriksa sintaks tanpa membangun struktur data, sehingga lebih murah untuk data besar:

php
<?php
$valid = '{"nama": "Budi", "umur": 28}';
$rusak = '{"nama": "Budi", "umur": 28,}';

echo (json_validate($valid) ? "valid" : "tidak valid") . "\n";
echo (json_validate($rusak) ? "valid" : "tidak valid") . "\n";

Output yang Dihasilkan:

text
valid
tidak valid

Variabel $rusak memuat koma menggantung sebelum kurung kurawal penutup — kesalahan tipikal hasil penyambungan string manual. Fungsi json_validate() mengembalikan true hanya apabila seluruh dokumen lolos pemeriksaan sintaks. Fungsi ini cocok dipasang di gerbang pipeline: berkas JSON yang tidak lolos pemeriksaan langsung ditolak sebelum diproses lebih jauh.

Penanganan Galat Dekode #

json_decode() yang gagal hanya mengembalikan null — tanpa exception, tanpa peringatan. Dua gaya penanganan galat berikut menghasilkan informasi yang jauh lebih berguna:

php
<?php
$rusak = '{"nama": "Budi", "umur": 28,}';

$hasil = json_decode($rusak);
if ($hasil === null && json_last_error() !== JSON_ERROR_NONE) {
    echo "Gaya manual  : " . json_last_error_msg() . "\n";
}

try {
    json_decode($rusak, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    echo "Gaya exception: " . $e->getMessage() . "\n";
}

Output yang Dihasilkan:

text
Gaya manual  : Syntax error
Gaya exception: Syntax error

Gaya pertama memanggil json_last_error() setelah dekode: apabila kode galatnya bukan JSON_ERROR_NONE, json_last_error_msg() memberikan pesan galat terakhir. Gaya kedua melewatkan flag JSON_THROW_ON_ERROR sehingga kegagalan dekode melempar JsonException yang bisa ditangkap try-catch — pendekatan yang lebih disarankan karena galat tidak mungkin terlupakan. Perlu dicatat pemeriksaan $hasil === null saja tidak cukup untuk gaya pertama, sebab JSON null yang sah juga didekode menjadi null; itulah alasan json_last_error() ikut diperiksa.

JSON vs serialize #

PHP juga punya mekanisme serialisasi native: serialize() dan unserialize(). Keduanya tidak saling menggantikan — pilihan bergantung pada kebutuhan:

AspekJSONserialize
Keterbacaan manusiaYa, mudah dibacaFormat internal PHP
Portabilitas antar bahasaUniversalHanya PHP
Struktur bertingkatObject dan arrayMendukung, termasuk object class
Memakai kembali object classTidak otomatisYa, dengan opsi allowed_classes

JSON menang untuk pertukaran data antar sistem dan penyimpanan yang mungkin dibaca alat lain. serialize() unggul saat menyimpan nilai PHP secara internal — misalnya isi cache — karena mampu mempertahankan class dan referensi.

Ringkasan #

json_decode() mengubah JSON menjadi object stdClass atau array asosiatif melalui parameter $associative; json_encode() mengubah data PHP menjadi JSON dengan flag JSON_UNESCAPED_UNICODE, JSON_UNESCAPED_SLASHES, dan JSON_PRETTY_PRINT untuk hasil yang ramah dibaca. json_validate() (PHP 8.3+) memeriksa keabsahan sintaks secara murah, sementara flag JSON_THROW_ON_ERROR mengubah kegagalan dekode menjadi JsonException yang mudah ditangani. Format data ketiga yang masih banyak dipakai di sistem lama dan API berbasis SOAP adalah XML — pembacaannya memiliki pendekatan tersendiri yang akan kita pelajari pada Chapter berikutnya.

Referensi #