D
P
0

WordPress & PHP

Fatal Error PHP 8: Baca Properti dari Array (`$obj->key`) Padahal Getter-nya Balikin Array

23 Juni 2026·4 menit baca
Fatal Error PHP 8: Baca Properti dari Array (`$obj->key`) Padahal Getter-nya Balikin Array

Sebuah platform booking berbasis WordPress yang saya bangun berjalan mulus selama berbulan-bulan. Lalu hosting menaikkan PHP dari 7.x ke 8, dan halaman detail listing langsung mati total — layar putih, fatal error. Pesannya jelas dan menusuk:

Fatal error: Uncaught Error: Attempt to read property "price" on array

Baris pemicunya ada di template part yang menampilkan harga listing. Kira-kira begini bentuknya:

$listing = get_listing_data( $id );
 
echo '<span class="price">' . $listing->price . '</span>';
echo '<span class="cap">'   . $listing->capacity . '</span>';

Sekilas tidak ada yang aneh. $listing->price, $listing->capacity — terlihat seperti akses properti objek yang wajar. Tapi justru di situ masalahnya: $listing bukan objek.

Kenapa ini terjadi

Getter dari plugin, get_listing_data( $id ), mengembalikan array asosiatif, bukan objek. Isinya kira-kira:

$listing = array(
    'price'    => 250000,
    'capacity' => 4,
    'gallery'  => array( /* ... */ ),
    // dan seterusnya — semuanya field meta
);

Jadi nilai harga sebenarnya ada di $listing['price'], bukan $listing->price.

Di PHP 7, mengakses properti objek pada sebuah array itu salah, tapi hanya melempar notice dan diam-diam menghasilkan null. Kode tetap jalan, halaman tetap tampil — cuma harganya kosong, dan kalau ada yang sempat memperhatikan, paling muncul peringatan di log. Bug-nya laten: sudah ada di sana sejak awal, tapi tidak pernah meledak.

PHP 8 mengubah aturannya. Akses properti pada array bukan lagi notice yang bisa diabaikan, melainkan Error yang fatal. Begitu interpreter ketemu $listing->price dan $listing ternyata array, eksekusi langsung berhenti. Tidak ada null diam-diam lagi. Bug yang sebelumnya tertidur tiba-tiba menjadi situs mati saat upgrade.

Yang bikin lebih runyam, ada masalah kedua yang ikut ketahuan begitu saya menggali. Di alur checkout ada guard untuk memvalidasi listing:

$listing = get_listing_data( $id );
 
if ( empty( $listing['id'] ) ) {
    // listing dianggap tidak valid -> redirect keluar dari checkout
    wp_safe_redirect( home_url() );
    exit;
}

Masalahnya: get_listing_data() hanya mengembalikan field meta. Tidak ada key 'id' di dalamnya sama sekali. Jadi empty( $listing['id'] ) selalu bernilai true untuk setiap listing — yang sah sekalipun. Guard ini menganggap semua listing tidak valid dan salah me-redirect orang keluar dari checkout. Ini bug logika yang berdiri sendiri, tidak ada hubungannya dengan versi PHP, tapi sumbernya sama persis: berasumsi soal bentuk data tanpa pernah benar-benar memeriksanya.

Perbaikannya

Perbaikan untuk fatal error-nya langsung: akses pakai sintaks array.

$listing = get_listing_data( $id );
 
echo '<span class="price">' . $listing['price'] . '</span>';
echo '<span class="cap">'   . $listing['capacity'] . '</span>';

Untuk guard checkout, saya berhenti mengandalkan key yang memang tidak pernah ada. Cara yang benar untuk memastikan sebuah listing itu eksis adalah bertanya ke WordPress langsung lewat get_post(), bukan menebak-nebak isi array meta:

$post = get_post( $id );
 
if ( ! $post || $post->post_type !== 'listing' ) {
    wp_safe_redirect( home_url() );
    exit;
}
 
$listing = get_listing_data( $id );

get_post() mengembalikan objek post sungguhan (atau null kalau tidak ada), jadi pengecekannya akurat dan checkout berhenti menendang keluar listing yang sah.

Satu hal lagi: beberapa template part memang butuh id dan title dari listing-nya. Daripada memaksa mereka membaca $listing->id (yang tidak ada) atau memanggil ulang ke mana-mana, saya suntikkan field itu ke dalam array setelah getter dipanggil, supaya template punya semua yang dibutuhkan dalam satu bentuk yang konsisten:

$post = get_post( $id );
 
$listing         = get_listing_data( $id );
$listing['id']   = $post->ID;
$listing['title'] = get_the_title( $post );

Sekarang template part bisa membaca $listing['id'] dan $listing['title'] dengan aman, dan tidak ada lagi yang berasumsi getter-nya mengembalikan objek.

Pelajaran

Konfirmasi bentuk nilai balik sebuah getter — array atau objek — sebelum kamu mengaksesnya. Nama seperti get_listing_data() tidak memberitahumu apa pun soal ini; satu-satunya cara tahu adalah membaca implementasinya atau var_dump() hasilnya sekali. Saya menganggap getter itu mengembalikan objek hanya karena "rasanya" seperti objek, dan asumsi itu bertahan diam-diam selama berbulan-bulan.

PHP 8 mengubah sejumlah notice lama menjadi fatal error, dan ini salah satu yang paling sering menggigit di proyek lawas. Mengakses properti pada array dulu hanya bisikan di log; sekarang dia mematikan halaman. Artinya, upgrade PHP bukan sekadar urusan kompatibilitas sintaks — dia membongkar setiap asumsi malas yang selama ini ditutupi oleh perilaku permisif PHP 7. Bug yang laten bertahun-tahun bisa berubah jadi situs down hanya karena satu kenaikan versi minor di panel hosting.

Pelajaran praktisnya: sebelum migrasi PHP 8, telusuri kode untuk pola -> pada nilai yang sumbernya array, dan jangan pernah memvalidasi keberadaan sesuatu lewat key yang belum kamu pastikan ada. Kalau mau tahu sebuah post eksis, tanyakan ke get_post() — bukan ke array meta yang kebetulan kamu pegang.