Anda seharusnya tidak menangkap pengecualian kecuali Anda bermaksud melakukan sesuatu yang berarti .
"Sesuatu yang bermakna" mungkin salah satunya:
Menangani pengecualian
Tindakan bermakna yang paling jelas adalah menangani pengecualian, misalnya dengan menampilkan pesan kesalahan dan membatalkan operasi:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Pembalakan atau pembersihan sebagian
Terkadang Anda tidak tahu bagaimana menangani dengan benar pengecualian dalam konteks tertentu; mungkin Anda kurang informasi tentang "gambaran besar", tetapi Anda ingin mencatat kegagalan sedekat mungkin dengan titik di mana hal itu terjadi. Dalam hal ini, Anda mungkin ingin menangkap, mencatat, dan melemparkan kembali:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
Skenario terkait adalah di mana Anda berada di tempat yang tepat untuk melakukan pembersihan untuk operasi yang gagal, tetapi tidak memutuskan bagaimana kegagalan harus ditangani di tingkat atas. Dalam versi PHP sebelumnya ini akan diimplementasikan sebagai
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
PHP 5.5 telah memperkenalkan finally
kata kunci, jadi untuk skenario pembersihan sekarang ada cara lain untuk mendekati ini. Jika kode pembersihan perlu dijalankan tidak peduli apa yang terjadi (mis. Baik pada kesalahan maupun kesuksesan) sekarang mungkin untuk melakukan ini sementara secara transparan memungkinkan segala pengecualian yang dilemparkan untuk disebarkan:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Abstraksi kesalahan (dengan chaining pengecualian)
Kasus ketiga adalah di mana Anda ingin mengelompokkan banyak kegagalan yang mungkin secara logis di bawah payung yang lebih besar. Contoh untuk pengelompokan logis:
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
Dalam hal ini, Anda tidak ingin pengguna Component
tahu bahwa itu diimplementasikan menggunakan koneksi database (mungkin Anda ingin menjaga opsi Anda terbuka dan menggunakan penyimpanan berbasis file di masa depan). Jadi spesifikasi Anda untuk Component
akan mengatakan bahwa "dalam kasus kegagalan inisialisasi, ComponentInitException
akan dibuang". Hal ini memungkinkan konsumen Component
untuk menangkap pengecualian dari tipe yang diharapkan sementara juga memungkinkan kode debug untuk mengakses semua detail (tergantung pada implementasi) .
Memberikan konteks yang lebih kaya (dengan chaining pengecualian)
Akhirnya, ada beberapa kasus di mana Anda mungkin ingin memberikan lebih banyak konteks untuk pengecualian. Dalam hal ini masuk akal untuk membungkus pengecualian di yang lain yang menampung lebih banyak informasi tentang apa yang Anda coba lakukan ketika kesalahan terjadi. Sebagai contoh:
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
Kasus ini mirip dengan yang di atas (dan contohnya mungkin bukan yang terbaik yang bisa muncul), tetapi menggambarkan titik memberikan lebih banyak konteks: jika pengecualian dilemparkan, ia memberi tahu kita bahwa salinan file gagal. Tetapi mengapa itu gagal? Informasi ini disediakan dalam pengecualian yang dibungkus (yang mungkin ada lebih dari satu tingkat jika contohnya jauh lebih rumit).
Nilai melakukan ini diilustrasikan jika Anda berpikir tentang skenario di mana misalnya membuat UserProfile
objek menyebabkan file akan disalin karena profil pengguna disimpan dalam file dan mendukung semantik transaksi: Anda dapat "membatalkan" perubahan karena hanya dilakukan pada Salin profil sampai Anda komit.
Dalam hal ini, jika Anda melakukannya
try {
$profile = UserProfile::getInstance();
}
dan akibatnya menangkap kesalahan pengecualian "Direktori target tidak dapat dibuat", Anda berhak untuk dibingungkan. Membungkus pengecualian "inti" ini di lapisan pengecualian lain yang menyediakan konteks akan membuat kesalahan lebih mudah untuk ditangani ("Membuat salinan profil gagal" -> "Operasi penyalinan file gagal" -> "Direktori target tidak dapat dibuat").
finally
konstruksi (setidaknya belum) ... Jadi itu keluar, yang berarti kita harus menggunakan hal-hal kotor seperti ini ...finally
di PHP.error_code
properti yang dapat diperiksa untuk mendapatkan kesalahan yang mendasarinya. kode. Jika Anda hanya mampu menangani beberapa kesalahan tersebut secara berarti, maka Anda mungkin ingin menangkap, memeriksa, dan jika Anda tidak dapat menangani kesalahan - rethrow.Yah, ini semua tentang menjaga abstraksi. Jadi saya sarankan menggunakan rantai pengecualian untuk melempar langsung. Sejauh mengapa, izinkan saya menjelaskan konsep abstraksi bocor
Katakanlah Anda sedang membangun model. Model ini seharusnya mengabstraksi semua ketekunan dan validasi data dari sisa aplikasi. Jadi sekarang apa yang terjadi ketika Anda mendapatkan kesalahan basis data? Jika Anda menata ulang
DatabaseQueryException
, Anda membocorkan abstraksi. Untuk memahami mengapa, pikirkan abstraksi sejenak. Anda tidak peduli bagaimana model menyimpan data, hanya saja itu terjadi. Demikian juga Anda tidak peduli apa yang salah dalam sistem yang mendasari model, hanya bahwa Anda tahu ada sesuatu yang salah, dan kira-kira apa yang salah.Jadi dengan memikirkan kembali DatabaseQueryException, Anda membocorkan abstraksi dan memerlukan kode panggilan untuk memahami semantik dari apa yang terjadi di bawah model. Sebagai gantinya, buatlah obat generik
ModelStorageException
, dan bungkus bagianDatabaseQueryException
dalamnya. Dengan begitu, kode panggilan Anda masih dapat mencoba menangani kesalahan secara semantik, tetapi tidak masalah teknologi yang mendasari Model karena Anda hanya mengekspos kesalahan dari lapisan abstraksi itu. Bahkan lebih baik, karena Anda membungkus pengecualian, jika itu gelembung sepanjang jalan dan perlu dicatat, Anda dapat melacak ke pengecualian akar dilemparkan (berjalan rantai) sehingga Anda masih memiliki semua informasi debug yang Anda butuhkan!Jangan hanya menangkap dan memikirkan kembali pengecualian yang sama kecuali Anda perlu melakukan beberapa post-processing. Tapi blok seperti
} catch (Exception $e) { throw $e; }
itu tidak ada gunanya. Tetapi Anda dapat membungkus kembali pengecualian untuk beberapa keuntungan abstraksi yang signifikan.sumber
IMHO, menangkap Pengecualian hanya untuk rethrow tidak berguna . Dalam hal ini, jangan menangkapnya, dan biarkan metode yang disebut sebelumnya menanganinya (alias metode yang 'atas' di tumpukan panggilan) .
Jika Anda mengolahnya kembali, merantai pengecualian yang tertangkap menjadi yang baru yang akan Anda lempar jelas merupakan praktik yang baik, karena akan menyimpan informasi yang terkandung di dalamnya. Namun, memikirkan kembali itu hanya berguna jika Anda menambahkan beberapa informasi atau menangani sesuatu dengan pengecualian yang ditangkap, mungkin itu beberapa konteks, nilai, logging, membebaskan sumber daya, apa pun.
Sebuah cara untuk menambahkan beberapa informasi untuk memperpanjang
Exception
kelas, untuk memiliki pengecualian sepertiNullParameterException
,DatabaseException
, dll Terlebih lagi, ini memungkinkan developper untuk hanya menangkap beberapa pengecualian bahwa ia dapat menangani. Misalnya, seseorang hanya dapat menangkapDatabaseException
dan mencoba untuk memecahkan apa yang menyebabkannyaException
, seperti menghubungkan kembali ke databse.sumber
Anda harus melihatnya Pengecualian Praktik Terbaik di PHP 5.3
Penanganan pengecualian di PHP bukanlah fitur baru. Di tautan berikut, Anda akan melihat dua fitur baru di PHP 5.3 berdasarkan pengecualian. Yang pertama adalah pengecualian bersarang dan yang kedua adalah serangkaian tipe pengecualian baru yang ditawarkan oleh ekstensi SPL (yang sekarang merupakan ekstensi inti dari runtime PHP). Kedua fitur baru ini telah masuk ke dalam buku praktik terbaik terbaik dan layak untuk diperiksa secara terperinci.
http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3
sumber
Anda biasanya berpikir seperti ini.
Kelas mungkin melempar banyak jenis pengecualian yang tidak cocok. Jadi Anda membuat kelas pengecualian untuk kelas atau tipe kelas itu dan membuangnya.
Jadi kode yang menggunakan kelas hanya harus menangkap satu jenis pengecualian.
sumber