Exception & try-catch
Tangani kegagalan modern: throw, try-catch-finally, dan exception sendiri.
Analogi: Jaring Pengaman Akrobat
Error biasa seperti terpeleset: program masih bisa lanjut terpincang. Exception seperti jatuh dari trapeze: tanpa jaring pengaman, pertunjukan berhenti total. try-catch adalah jaringnya: bungkus aksi berisiko di try, siapkan rencana darurat di catch, dan program selamat dengan elegan.
Kenapa tidak cukup if? Karena if mengecek kondisi yang bisa diprediksi. Exception untuk kegagalan yang tidak bisa dicegah di awal: database tiba-tiba mati, API timeout, file hilang di tengah jalan. Tanpa exception, setiap fungsi harus mengembalikan kode error dan setiap pemanggil harus mengeceknya: kode tenggelam dalam pengecekan.
<?php
// Contoh 1: pola try-catch-finally
function ambilUser(int $id): array {
if ($id <= 0) {
throw new InvalidArgumentException("ID harus positif");
}
// ... query database ...
throw new RuntimeException("Database tidak merespons");
}
try {
$user = ambilUser(-5);
echo "Nama: " . $user["nama"];
} catch (InvalidArgumentException $e) {
echo "Input salah: " . $e->getMessage();
} catch (RuntimeException $e) {
echo "Coba lagi nanti, server sibuk.";
} finally {
// SELALU jalan: tutup koneksi, bebaskan lock, catat log
echo " [selesai]";
}throw melempar exception, eksekusi langsung melompat ke catch yang tipenya cocok. finally selalu jalan (sukses maupun gagal): tempat wajib untuk bersih-bersih resource. Urutan catch penting: spesifik dulu, umum belakangan, karena catch pertama yang cocok menang.
<?php
// Contoh 2: exception custom untuk domain bisnis
class StokHabisException extends Exception {}
class SaldoKurangException extends Exception {}
function checkout(array $keranjang, float $saldo): void {
foreach ($keranjang as $item) {
if ($item["stok"] === 0) {
throw new StokHabisException($item["nama"] . " habis");
}
}
$total = array_sum(array_column($keranjang, "harga"));
if ($saldo < $total) {
throw new SaldoKurangException("Kurang Rp" . number_format($total - $saldo));
}
// ... kurangi stok, catat transaksi ...
}
try {
checkout($keranjang, 50000);
echo "Checkout berhasil!";
} catch (StokHabisException | SaldoKurangException $e) {
// multi-catch: dua tipe, satu penanganan
echo "Gagal checkout: " . $e->getMessage();
}Exception custom (class kosong extends Exception) membuat penanganan per kasus bisnis menjadi presisi: tangkap StokHabisException untuk tawarkan produk lain, tangkap SaldoKurangException untuk arahkan ke top-up.
Jebakan yang Sering Terjadi
Catch kosong yang menelan error. catch (Exception $e) {} tanpa isi membuat kegagalan hilang tanpa jejak: data tidak tersimpan tapi user mengira berhasil. Minimal catat ke log di dalam catch.
Menangkap Throwable terlalu luas. catch (Throwable $e) menangkap semuanya termasuk fatal error yang seharusnya menghentikan program (misalnya kehabisan memori). Tangkap exception yang spesifik dan kamu tahu cara menanganinya; biarkan yang lain naik ke handler global.
Retry: Coba Lagi dengan Bijak
Untuk kegagalan sementara (API timeout, database sibuk), pola retry dengan jeda:
<?php
function denganRetry(callable $aksi, int $maksimal = 3): mixed {
$percobaan = 0;
while (true) {
try {
return $aksi();
} catch (RuntimeException $e) {
$percobaan++;
if ($percobaan >= $maksimal) throw $e; // menyerah
sleep($percobaan); // jeda makin lama: 1s, 2s, ...
}
}
}
$hasil = denganRetry(fn() => panggilApi(), 3);Jeda bertambah (exponential backoff) memberi server waktu pulih. Jangan retry untuk error permanen (data tidak valid): hanya untuk kegagalan sementara. Dan selalu batasi maksimal percobaan agar tidak loop selamanya.
Catatan teknis: Sejak PHP 7, fatal error seperti memanggil method yang tidak ada melempar
Error(bukanException). Keduanya turunanThrowable. Itu sebabnyacatch (Exception $e)tidak menangkap "Call to undefined method": butuhcatch (Error $e)ataucatch (Throwable $e).
Tantangan
Validasi dengan exception
Buat fungsi daftar($nama, $umur) yang throw Exception jika nama < 3 karakter ("Nama terlalu pendek") atau umur < 5 ("Umur tidak valid"). Panggil dalam try-catch untuk 3 data: 1 valid, 2 gagal berbeda. Tampilkan pesan masing-masing.