คุณไม่ควรจับข้อยกเว้น เว้นแต่คุณตั้งใจจะทำบางสิ่งบางอย่างที่มีความหมาย
"สิ่งที่มีความหมาย" อาจเป็นหนึ่งในสิ่งเหล่านี้:
จัดการข้อยกเว้น
การกระทำที่มีความหมายชัดเจนที่สุดคือการจัดการข้อยกเว้นเช่นโดยแสดงข้อความแสดงข้อผิดพลาดและยกเลิกการดำเนินการ:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
การบันทึกหรือล้างข้อมูลบางส่วน
บางครั้งคุณไม่ทราบวิธีจัดการข้อยกเว้นอย่างถูกต้องในบริบทเฉพาะ บางทีคุณอาจขาดข้อมูลเกี่ยวกับ "ภาพรวม" แต่คุณต้องการบันทึกความล้มเหลวใกล้กับจุดที่เกิดขึ้นมากที่สุด ในกรณีนี้คุณอาจต้องการจับบันทึกและโยนใหม่:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
สถานการณ์ที่เกี่ยวข้องคือที่ที่คุณอยู่ในสถานที่ที่เหมาะสมในการดำเนินการล้างข้อมูลสำหรับการดำเนินการที่ล้มเหลว แต่ไม่ต้องตัดสินใจว่าควรจัดการความล้มเหลวที่ระดับบนสุดได้อย่างไร ในเวอร์ชัน PHP ก่อนหน้านี้จะถูกนำมาใช้เป็น
$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 ได้เปิดตัวfinally
คำหลักดังนั้นสำหรับสถานการณ์การล้างข้อมูลขณะนี้มีวิธีอื่นในการเข้าถึง หากโค้ดการล้างข้อมูลต้องทำงานไม่ว่าจะเกิดอะไรขึ้น (เช่นทั้งข้อผิดพลาดและความสำเร็จ) ขณะนี้คุณสามารถทำเช่นนี้ได้ในขณะที่โปร่งใสอนุญาตให้มีข้อยกเว้นที่ถูกโยนทิ้งเพื่อเผยแพร่:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
เกิดข้อผิดพลาด (ยกเว้นการโยง)
กรณีที่สามคือที่ที่คุณต้องการจัดกลุ่มความล้มเหลวที่เป็นไปได้หลายอย่างภายใต้ร่มขนาดใหญ่ ตัวอย่างสำหรับการจัดกลุ่มแบบลอจิคัล:
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);
}
}
}
ในกรณีนี้คุณไม่ต้องการให้ผู้ใช้Component
ทราบว่ามีการใช้งานโดยใช้การเชื่อมต่อฐานข้อมูล (บางทีคุณอาจต้องการให้ตัวเลือกของคุณเปิดอยู่และใช้ที่เก็บข้อมูลแบบไฟล์ในอนาคต) ดังนั้นสเปคของคุณสำหรับComponent
จะบอกว่า "ในกรณีของความล้มเหลวในการเริ่มต้นComponentInitException
จะถูกโยน" สิ่งนี้ช่วยให้ผู้บริโภคComponent
จับข้อยกเว้นของชนิดที่คาดไว้ในขณะที่ยังอนุญาตให้การดีบักรหัสเพื่อเข้าถึงรายละเอียดทั้งหมด (ขึ้นอยู่กับการนำไปใช้)รายละเอียด
ให้บริบทที่สมบูรณ์ยิ่งขึ้น (ยกเว้นการโยง)
ในที่สุดก็มีหลายกรณีที่คุณอาจต้องการให้บริบทเพิ่มเติมสำหรับข้อยกเว้น ในกรณีนี้มันสมเหตุสมผลที่จะรวมข้อยกเว้นไว้ในอีกอันหนึ่งซึ่งเก็บข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่คุณพยายามทำเมื่อเกิดข้อผิดพลาด ตัวอย่างเช่น:
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);
}
}
}
กรณีนี้คล้ายกับด้านบน (และตัวอย่างอาจไม่ใช่สิ่งที่ดีที่สุดที่จะเกิดขึ้น) แต่มันแสดงให้เห็นถึงจุดที่ให้บริบทเพิ่มเติม: หากมีการโยนข้อยกเว้นจะเป็นการบอกเราว่าการคัดลอกไฟล์ล้มเหลว แต่ทำไมมันถึงล้มเหลว ข้อมูลนี้มีให้ในข้อยกเว้นที่ห่อ (ซึ่งอาจมีมากกว่าหนึ่งระดับหากตัวอย่างมีความซับซ้อนมากขึ้น)
มูลค่าของการทำเช่นนี้จะแสดงให้เห็นถ้าคุณคิดเกี่ยวกับสถานการณ์ที่เช่นการสร้าง UserProfile
วัตถุทำให้ไฟล์ถูกคัดลอกเนื่องจากโปรไฟล์ผู้ใช้ถูกเก็บไว้ในไฟล์และสนับสนุนความหมายของการทำธุรกรรม: คุณสามารถเปลี่ยนแปลง "เลิกทำ" ได้เนื่องจากพวกเขาเท่านั้น คัดลอกโปรไฟล์จนกว่าคุณจะยอมรับ
ในกรณีนี้ถ้าคุณทำ
try {
$profile = UserProfile::getInstance();
}
และเนื่องจากข้อผิดพลาดข้อยกเว้น "เป้าหมายไดเรกทอรีไม่สามารถสร้างได้" คุณจะมีสิทธิ์สับสนได้ การตัดข้อยกเว้น "แกนกลาง" นี้ในเลเยอร์ของข้อยกเว้นอื่น ๆ ที่ให้บริบทจะทำให้เกิดข้อผิดพลาดได้ง่ายขึ้น ("การสร้างการคัดลอกโปรไฟล์ล้มเหลว" -> "การดำเนินการคัดลอกไฟล์ล้มเหลว" -> "ไม่สามารถสร้างไดเรกทอรีเป้าหมาย")