errorexceptionMahir4 mnt baca

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
<?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
<?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
<?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 (bukan Exception). Keduanya turunan Throwable. Itu sebabnya catch (Exception $e) tidak menangkap "Call to undefined method": butuh catch (Error $e) atau catch (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.