Data opsional dalam aplikasi sering membentuk rantai: seorang pelanggan mungkin punya alamat, alamat tersebut mungkin punya kota. Ketika salah satu mata rantai bernilai null, akses lanjutan dengan tanda panah biasa (->) langsung menghentikan program dengan fatal error. Nullsafe operator (?->), yang hadir sejak PHP 8.0, memungkinkan kita menulis akses berantai tersebut dalam satu ekspresi yang aman: jika objeknya null, hasil seluruh rantai adalah null — bukan error. Pada Chapter ini kita akan mempelajari cara kerja ?->, cara menggabungkannya dengan ??, serta batasan-batasan pentingnya.

Sebelum mulai, kita perlu sedikit konteks tentang class dan object karena ?-> hanya relevan di sana. Class adalah cetak biru objek; properti adalah variabel di dalam objek; dan method adalah fungsi di dalam objek. Operator -> dipakai untuk mengakses keduanya: $pelanggan->nama membaca properti $nama, sedangkan $pelanggan->kota() memanggil method kota(). Materi lengkapnya ada di Section Object-Oriented Programming; untuk Chapter ini cukup tiga contoh class kecil di bawah sudah lebih dari cukup.

Masalah Akses pada Objek null #

Perhatikan class Alamat yang punya method kota(), dan class Pelanggan yang properti $alamat-nya boleh null (ditandai tipe ?Alamat). Ketika properti tersebut memang null, akses method di bawahnya menjadi bencana:

php
<?php
class Alamat {
    public function kota(): string {
        return "Bandung";
    }
}

class Pelanggan {
    public ?Alamat $alamat = null;
}

$budi = new Pelanggan();

echo $budi->alamat->kota();

Kode di atas lolos pemeriksaan sintaks, tetapi gagal total saat dijalankan karena $budi->alamat bernilai null:

text
Fatal error: Uncaught Error: Call to a member function kota() on null in contoh.php on line 13

Pesan di atas diambil dari eksekusi nyata — nama berkas dan nomor baris di komputer Anda akan menyesuaikan lokasi penulisan tersebut.

Pesan Call to a member function kota() on null berarti PHP diminta memanggil method pada “bukan objek”. Selama bertahun-tahun solusinya adalah memeriksa null secara manual di setiap tingkat rantai — membengkak dan membosankan bila rantainya panjang. Perilaku fatal error ini juga menjadi alasan kenapa pengecekan null pada objek opsional termasuk rutinitas paling sering ditulis di aplikasi nyata.

Solusi dengan Operator ?-> #

Nullsafe operator mengubah tanda panah -> menjadi ?->: jika operand kirinya bukan null, akses berjalan normal; jika null, ekspresi menghasilkan null tanpa error:

php
<?php
class Alamat {
    public function kota(): string {
        return "Bandung";
    }
}

class Pelanggan {
    public ?Alamat $alamat = null;
}

$siti = new Pelanggan();
$siti->alamat = new Alamat();

$budi = new Pelanggan();

echo ($siti->alamat?->kota() ?? "alamat kosong") . "\n";
echo ($budi->alamat?->kota() ?? "alamat kosong") . "\n";

Output yang Dihasilkan:

text
Bandung
alamat kosong

Mari kita bedah baris-baris kuncinya:

  1. Baris 12-13 ($siti): properti $alamat diisi objek Alamat sungguhan, sehingga $siti->alamat?->kota() mengevaluasi kota() secara normal dan menghasilkan "Bandung".
  2. Baris 15 ($budi): properti $alamat tetap null. Tanda ?-> mendeteksi hal tersebut dan langsung menghasilkan null — method kota() tidak pernah dipanggil, tidak ada fatal error.
  3. Baris 17-18: kombinasi dengan ?? dari Chapter Null Coalescing Operator mengubah null menjadi teks cadangan "alamat kosong".

Tanpa ?->, kita membutuhkan pemeriksaan if bersarang untuk kasus dua tingkat ini, dan pemeriksaan bertambah setiap kali rantai bertambah satu tingkat. Dengan ?->, panjang rantai tidak mengubah kompleksitas kode sama sekali.

Rantai Akses yang Lebih Panjang #

Kekuatan sesungguhnya baru terasa pada rantai multi-tingkat. Perhatikan tiga class berikut: Profil berisi ?Kota, dan Kota berisi ?Negara. Mengambil kode mata uang dari profil berarti melintasi dua mata rantai yang sama-sama bisa null:

php
<?php
class Negara {
    public function kodeMataUang(): string {
        return "IDR";
    }
}

class Kota {
    public ?Negara $negara = null;
}

class Profil {
    public ?Kota $kota = null;
}

$profil = new Profil();

var_dump($profil->kota?->negara?->kodeMataUang());

$profil->kota = new Kota();
$profil->kota->negara = new Negara();

echo ($profil->kota?->negara?->kodeMataUang() ?? "mata uang tidak diketahui") . "\n";

Output yang Dihasilkan:

text
NULL
IDR

Saat $profil->kota masih null, ekspresi $profil->kota?->negara?->kodeMataUang() langsung menghasilkan null — sisa rantai di sebelah kanannya (termasuk pemanggilan kodeMataUang()) tidak dievaluasi sama sekali. Setelah kedua mata rantai terisi objek, hasilnya "IDR". Perhatikan bahwa pemberian nilai di baris 15-16 tetap memakai -> biasa; ?-> hanya berperan di sisi pembacaan nilai.

Sifat “menghentikan seluruh rantai” ini berlaku juga saat ?-> dicampur dengan -> biasa. Ekspresi $profil->kota?->negara->kodeMataUang() (hanya tanda panah pertama yang nullsafe) tetap menghasilkan null tanpa error ketika $profil->kota adalah null, karena evaluasi seluruh ekspresi berhenti di titik tersebut.

Hanya null yang Di-skip #

Nullsafe operator menyingkat jalur untuk null — bukan untuk nilai lain yang dianggap falsy PHP. Jika objeknya ada, method di dalamnya tetap dipanggil sekalipun nilai kembaliannya nol atau string kosong:

php
<?php
class Keranjang {
    public function totalItem(): int {
        return 0;
    }
}

class Pengguna {
    public ?Keranjang $keranjang = null;
}

$pengguna = new Pengguna();
$pengguna->keranjang = new Keranjang();

var_dump($pengguna->keranjang?->totalItem());
var_dump($pengguna->keranjang?->totalItem() ?? "keranjang kosong");

$penggunaLain = new Pengguna();
var_dump($penggunaLain->keranjang?->totalItem() ?? "keranjang kosong");

Output yang Dihasilkan:

text
int(0)
int(0)
string(16) "keranjang kosong"

Baris var_dump pertama membuktikan method totalItem() benar-benar dieksekusi dan mengembalikan int(0). Baris kedua memperlihatkan jebakan klasik: 0 ?? "keranjang kosong" tetap menghasilkan int(0) karena 0 bukan null — operator ?? tidak menggantinya. Hanya pada baris terakhir, ketika $keranjang benar-benar null, nilai cadangan "keranjang kosong" yang muncul. Logika ?-> dan ?? sama-sama hanya mengurus null; keduanya sengaja tidak menyentuh nilai falsy lain (pembahasan lengkap ada di Chapter Truthiness dan Short-Circuit ).

Batasan Operator Nullsafe #

Nullsafe operator adalah operator pembacaan nilai, bukan penulisan. PHP menolak ?-> di sisi kiri tanda sama dengan (=), sehingga kode berikut tidak pernah berhasil dijalankan:

php
<?php
class Pelanggan {
    public ?string $nama = null;
}

$pelanggan = null;

$pelanggan?->nama = "Budi";

Pesan fatal yang muncul saat kode di atas dijalankan:

text
Fatal error: Can't use nullsafe operator in write context in contoh.php on line 8

Pesan di atas diambil dari eksekusi nyata dengan kode blok sebelumnya disimpan sebagai contoh.php; nomor baris di komputer Anda menyesuaikan. Alasannya masuk akal: bila $pelanggan adalah null, tidak ada objek yang bisa menampung penugasan nama = "Budi", jadi PHP memilih menolaknya di awal daripada diam-diam membuang nilai. Untuk mengisi properti, pastikan objeknya ada lebih dulu — misalnya dengan membuat objek terlebih dahulu seperti contoh $siti->alamat = new Alamat(); di atas.

Selain itu, ?-> hanya boleh dipakai saat Anda tidak peduli perbedaan antara “objeknya null” dan “objeknya ada”. Bila kedua kasus tersebut butuh perlakuan berbeda — misalnya mencatat log khusus untuk data yang hilang — tulis pemeriksaan null eksplisit agar logika terlihat jelas. Berkas contoh.php pada bagian bawah halaman merangkum pola-pola aman dari Chapter ini dalam satu program utuh.

Ringkasan #

Operator ?-> mengevaluasi akses method atau properti hanya bila objek di kirinya bukan null; jika null, seluruh rantai ekspresi berhenti dan menghasilkan null tanpa error. Kombinasi ?-> dengan ?? menghasilkan pola baca data opsional berantai yang ringkas dan aman, sementara penugasan tetap membutuhkan objek yang benar-benar ada. Selanjutnya kita berpindah ke operator pemilih nilai yang bekerja pada kondisi umum: ternary operator.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

contoh.php

Unduh berkas
php
<?php
// contoh.php — rangkuman Nullsafe Operator
// Jalankan dengan: php contoh.php

class Alamat {
    public function kota(): string {
        return "Bandung";
    }
}

class Pelanggan {
    public ?Alamat $alamat = null;
}

$siti = new Pelanggan();
$siti->alamat = new Alamat();

$budi = new Pelanggan();

echo "Kota Siti : " . ($siti->alamat?->kota() ?? "alamat kosong") . "\n";
echo "Kota Budi : " . ($budi->alamat?->kota() ?? "alamat kosong") . "\n";

// Rantai multi-tingkat
class Negara {
    public function kodeMataUang(): string {
        return "IDR";
    }
}

class Kota {
    public ?Negara $negara = null;
}

class Profil {
    public ?Kota $kota = null;
}

$profil = new Profil();
echo "Mata uang  : " . var_export($profil->kota?->negara?->kodeMataUang(), true) . "\n";

$profil->kota = new Kota();
$profil->kota->negara = new Negara();
echo "Mata uang  : " . ($profil->kota?->negara?->kodeMataUang() ?? "mata uang tidak diketahui") . "\n";

// Hanya null yang di-skip: method tetap dipanggil walau hasilnya 0
class Keranjang {
    public function totalItem(): int {
        return 0;
    }
}

class Pengguna {
    public ?Keranjang $keranjang = null;
}

$pengguna = new Pengguna();
$pengguna->keranjang = new Keranjang();
echo "Keranjang  : " . var_export($pengguna->keranjang?->totalItem(), true) . "\n";

$penggunaLain = new Pengguna();
echo "Keranjang  : " . ($penggunaLain->keranjang?->totalItem() ?? "keranjang kosong") . "\n";