Gejalanya bikin saya garuk-garuk kepala: di sebuah situs editorial yang saya port dari React ke WordPress, ada satu bagian "dossier" yang seharusnya kaya data dari post meta, tapi yang muncul selalu konten demo. Selamanya. Tidak ada error, tidak ada warning, tidak ada PHP notice di log. Halaman render mulus, statusnya 200, cuma isinya salah. Dan yang paling menyebalkan: ini kelihatan persis seperti bug importer, padahal importer-nya baik-baik saja.
Di React, logikanya sesederhana ini:
const value = deepMeta ?? fallback;Kalau deepMeta ada, pakai itu. Kalau null/undefined, baru pakai fallback. Satu baris, jelas, tidak ada celah.
Pas saya pindahkan ke PHP, tangan saya yang menulisnya begini:
$value = $deepMeta;
// ... beberapa baris di antaranya ...
$value = $fallback;Saya pakai $value yang sama untuk dua hal yang berbeda: pertama untuk kandidat hasil decode meta, lalu untuk nilai final. Dan baris kedua jalan tanpa syarat apa pun.
Kenapa ini terjadi
Inti masalahnya ada di kata "tanpa syarat". Di React, ?? itu operator: dia memutuskan. $value = $fallback; di PHP bukan operator apa-apa — itu cuma assignment biasa yang selalu dieksekusi tiap kali baris itu dilewati. Jadi alurnya:
$deepMeta = get_post_meta( $post_id, 'dossier_data', true ); // ADA isinya
$value = $deepMeta; // bagus, $value sekarang berisi data asli
// ... logika lain, format, escape, dsb ...
$value = $fallback; // BOOM — menimpa data asli, tiap kali, tanpa peduliKarena baris terakhir tidak dibungkus kondisi apa pun, dia menghapus cabang "deep" bahkan ketika meta-nya jelas-jelas ada. Importer sudah benar mengisi post meta, decode-nya juga benar, $deepMeta benar-benar terisi — lalu satu baris polos di bawahnya mengganti semuanya dengan demo.
Yang bikin ini licin: tidak ada yang salah secara sintaksis. PHP tidak punya alasan untuk komplain. Menimpa variabel yang sudah ada nilainya adalah hal paling normal di dunia. Tidak ada undefined, tidak ada type error, tidak ada null. Cuma nilai yang benar, lalu satu detik kemudian, nilai yang salah. Output yang keliru itu sama sekali tidak meninggalkan jejak.
Saya kehilangan waktu justru karena saya curiga ke tempat yang salah. Saya bongkar importer, saya var_dump hasil get_post_meta, saya cek apakah key meta-nya benar. Semua hijau. $deepMeta selalu terisi pas saya dump. Yang tidak saya sadari adalah saya men-dump di atas baris penimpa itu, jadi saya cuma membuktikan bahwa data masuk — bukan bahwa data bertahan sampai output.
Perbaikannya
Begitu saya dump tepat sebelum echo, semuanya langsung kelihatan: nilainya sudah jadi fallback. Saya scroll ke atas, dan di situ baris $value = $fallback; yang tidak bersyarat menatap balik.
Solusinya gampang dan harusnya jadi refleks: jangan pernah pakai satu variabel untuk "kandidat" sekaligus "final". Beri nama yang berbeda, dan baru terapkan fallback kalau kandidatnya memang kosong.
$deep_value = get_post_meta( $post_id, 'dossier_data', true );
if ( empty( $deep_value ) ) {
$value = $fallback;
} else {
$value = $deep_value;
}
echo $value;$deep_value memegang kandidat hasil decode meta, $value memegang nilai final, dan assignment fallback sekarang dijaga oleh empty(). Fallback cuma jalan kalau memang tidak ada data dalam — persis seperti ?? di React aslinya. Begitu deploy, bagian dossier langsung render data asli yang sebenarnya sudah ada di database dari awal.
Kalau mau lebih ringkas, PHP modern juga punya null coalescing yang menjaga semangat baris React itu dalam satu ekspresi:
$value = ! empty( $deep_value ) ? $deep_value : $fallback;Yang penting bukan gayanya, tapi prinsipnya: keputusan "pakai yang mana" harus ada di satu tempat, bukan tersebar jadi dua assignment terpisah yang salah satunya jalan tanpa syarat.
Pelajaran
Bug paling mahal sering kali yang paling sunyi. Tidak ada stack trace yang menuntun, tidak ada baris merah di log — cuma output yang salah dan terlihat masuk akal, sampai kamu benar-benar membandingkannya dengan yang seharusnya.
Pelajaran konkret yang saya bawa: jangan pernah me-reuse satu variabel untuk peran "kandidat" dan "final" sekaligus. Assignment tak bersyarat yang muncul belakangan adalah silent clobber — tidak ada error yang akan mengungkapnya. Operator seperti ?? di JavaScript menyatukan keputusan dan penugasan jadi satu, jadi mustahil "lupa" syaratnya. Begitu kamu menerjemahkannya jadi dua baris terpisah di PHP, syarat itu jadi tanggung jawabmu, dan gampang sekali rontok.
Dan satu trik debugging: kalau output salah tapi data sumbernya benar, dump nilainya tepat sebelum dipakai, bukan tepat setelah diambil. Jarak antara "data masuk" dan "data dipakai" itulah tempat clobber bersembunyi.
