การจัดการความผิดพลาด PHP

ความผิดพลาด (Exception) ใช้เพื่อเปลี่ยนแปลงกระบวนการทำงานปกติของสคริปต์ เมื่อเกิดความผิดพลาดที่กำหนด

อะไรคือความผิดพลาด?

PHP 5 ได้นำเสนอวิธีการจัดการความผิดพลาดที่เป็นมุมมองทางโอปเปอร์เรียน

การจัดการความผิดพลาดใช้เพื่อเปลี่ยนแปลงกระบวนการทำงานปกติของสคริปต์ เมื่อเกิดความผิดพลาด (หรือความผิดพลาด) ในสถานการณ์ที่กำหนด

เมื่อความผิดพลาดที่ถูกทำงานจะเกิดขึ้น ทั่วไปแล้วจะเกิดปรากฏการณ์ดังนี้:

  • สถานะการทำงานของโค้ดจะถูกบันทึก
  • การทำงานของโค้ดจะเปลี่ยนไปยังฟังก์ชันปฏิบัติการฝ่ายความผิดพลาดที่กำหนดไว้ก่อน
  • ตามสถานการณ์ ปฏิบัติการจะทำงานที่เริ่มต้นจากสถานะระบบที่เก็บไว้ หยุดการปฏิบัติการสคริปต์ หรือทำงานต่อจากสถานที่อื่นในโค้ด

เราจะแสดงวิธีการจัดการความผิดพลาดแบบต่างๆ:

  • การใช้ความผิดพลาดพื้นฐาน
  • สร้างปฏิบัติการฝ่ายความผิดพลาดที่กำหนดเอง
  • ข้อผิดพลาดหลายข้อ
  • ทิ้งข้อผิดพลาดอีกครั้ง
  • ตั้งปฏิบัติการฝ่ายความผิดพลาดระดับสูงสุด

การใช้ความผิดพลาดพื้นฐาน

เมื่อความผิดพลาดที่ถูกทิญยาย โค้ดต่อไปจะไม่ทำงานต่อ PHP จะพยายามหาบล็อค "catch" ที่ตรงกัน

ถ้าความผิดพลาดไม่ถูกจับและไม่ได้ใช้ set_exception_handler() ที่จะจัดการด้วย จะเกิดความผิดพลาดรุนแรง (เศษ) และมีข้อความข้อผิดพลาด "Uncaught Exception" (ความผิดพลาดที่ไม่ถูกจับ)

ขอให้เราทดลองทิญยายความผิดพลาด โดยไม่ได้จับมัน

<?php
//create function with an exception
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }
//trigger exception
checkNum(2);
?>

โค้ดดังกล่าวจะได้ความผิดพลาดคล้ายนี้:

Fatal error: Uncaught exception 'Exception' 
ข้อความ 'Value must be 1 or below' ใน C:\webfolder\test.php:6 
Stack trace: #0 C:\webfolder\test.php(12): 
checkNum(28) #1 {main} โทษใน C:\webfolder\test.php บรรทัด 6

Try, throw และ catch

เพื่อป้องกันความผิดพลาดที่เกิดขึ้นในตัวอย่างดังกล่าว เราต้องเขียนโค้ดที่มีการจัดการความผิดพลาด

ปฏิบัติการที่ถูกต้องควรรวมถึง:

  1. แบบทดลอง - ฟังก์ชันที่ใช้ความผิดพลาดควรอยู่ในบล็อค "try" ถ้าไม่มีความผิดพลาดที่จะดำเนินการ โค้ดจะทำงานตามปกติ แต่ถ้ามีความผิดพลาดที่จะดำเนินการ จะมีการทิญยายความผิดพลาด
  2. Throw - นี่เป็นการกำหนดว่าจะทิ้งความผิดพลาดอย่างไร ทุกตัว "throw" ต้องมีคู่ "catch" อย่างน้อยหนึ่ง
  3. Catch - บล็อค "catch" จะจับความผิดพลาด และสร้าง object ที่มีข้อมูลของความผิดพลาด

จะมีการทำให้เกิดความผิดพลาด:

<?php
// สร้างฟังก์ชันที่สามารถทิ้งความผิดพลาดได้
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }
// กระทำที่ทำให้เกิดความผิดพลาดในบล็อค "try"
try
 {
 checkNum(2);
 // ถ้ามีการทิ้งความผิดพลาด ข้อความนี้จะไม่ถูกแสดง
 echo 'If you see this, the number is 1 or below';
 }
// จับความผิดพลาด
catch(Exception $e)
 {
 echo 'Message: ' .$e->getMessage();
 }
?>

รหัสที่ขึ้นไปจะได้ข้อผิดพลาดเช่นนี้

Message: Value must be 1 or below

ตัวอย่างอธิบาย:

รหัสที่ขึ้นไปทิ้งความผิดพลาดและจับมันเอาไว้

  1. สร้างฟังก์ชัน checkNum() มันตรวจสอบว่าตัวเลขเป็นมากกว่า 1 หรือไม่ ถ้าเป็น ก็จะทิ้งความผิดพลาด
  2. เรียกฟังก์ชัน checkNum() ในบล็อค "try"
  3. ความผิดพลาดที่ฟังก์ชัน checkNum() ขึ้น
  4. บล็อค "catch" รับความผิดพลาดนี้ และสร้าง object ที่มีข้อมูลของความผิดพลาด ($e)
  5. ผ่านการเรียก $e->getMessage() จาก object exception จะทำให้มีข้อความของ exception ออกมา

อย่างไรก็ตาม เพื่อปฏิบัติตามหลักการ "ทุกตัว throw ต้องมีตัว catch ตอบกลับ" สามารถตั้งตัว handler ระดับสูงเพื่อจัดการข้อผิดพลาดที่ขาดไป

สร้างคลาส Exception ที่กำหนดเอง

การสร้าง exception ที่กำหนดเอง ง่ายมากเพียงแค่สร้างคลาสพิเศษ ที่เมื่อมีการเกิด exception ใน PHP สามารถเรียกฟังก์ชันของมันได้ คลาสนี้ต้องเป็น extension ของ exception คลาส

คลาส exception ที่กำหนดเองนี้ 继承了 PHP 的 exception คลาส ทุกๆ คุณสมบัติ คุณสามารถเพิ่มฟังก์ชันที่กำหนดเองได้

เราเริ่มที่จะสร้างคลาส exception:

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //ข้อความข้อผิดพลาด
  $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
  : <b>'.$this->getMessage().'</b> ไม่ใช่ที่อยู่อีเมลที่ถูกต้อง
  return $errorMsg;
  }
 }
$email = "someone@example...com";
try
 {
 //check if 
 if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
  {
  //ทิ้งข้อผิดพลาดถ้าอีเมล์ไม่ถูกต้อง
  throw new customException($email);
  }
 }
catch (customException $e)
 {
 //แสดงข้อความข้อผิดพลาดที่กำหนด
 echo $e->errorMessage();
 }
?>

คลาสใหม่นี้เป็นสำเนาของคลาส exception โบราณ ที่มีฟังก์ชัน errorMessage() พวกมันเป็นสำเนาของคลาสโบราณ ดังนั้นมันจะสืบทอดคุณสมบัติและวิธีจากคลาสโบราณ พวกเราสามารถใช้วิธีของคลาส exception อย่างเช่น getLine() , getFile() และ getMessage()

ตัวอย่างอธิบาย:

รหัสบทที่แสดงข้อผิดพลาดหนึ่ง และจับกุมมันด้วยคลาส exception ที่กำหนด

  1. คลาส customException ถูกสร้างขึ้นเพื่อขยายคลาส exception อันเดิม ดังนั้นมีการสืบทอดและใช้รูปแบบและวิธีทั้งหมดของคลาสเดิม
  2. สร้างฟังก์ชัน errorMessage() ซึ่งถ้าที่อยู่อีเมลที่ผิดทางกฎหมาย ฟังก์ชันนี้จะกลับค่าข้อความข้อผิดพลาด
  3. ตั้งค่าตัวแปร $email ให้เป็นตัวแปรของที่อยู่อีเมลที่ผิดทางกฎหมาย
  4. ปฏิบัติบล็อค "try" จากที่อยู่อีเมลที่ผิดทางกฎหมาย จะทิ้งข้อผิดพลาด
  5. บล็อค "catch" จับกุมข้อผิดพลาดและแสดงข้อความข้อผิดพลาด

ข้อผิดพลาดหลายข้อ

คุณสามารถใช้ข้อผิดพลาดหลายข้อสำหรับบล็อคสคริปต์หนึ่ง เพื่อตรวจสอบสถานการณ์หลายรายการ

คุณสามารถใช้บล็อค if..else หลายบล็อค หรือบล็อค switch หนึ่ง หรือนำข้อผิดพลาดภายในกัน พวกนี้สามารถใช้หลายคลาส exception และแสดงข้อความข้อผิดพลาดที่ต่างกัน

<?php
class customException extends Exception
{
public function errorMessage()
{
//ข้อความข้อผิดพลาด
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
: <b>'.$this->getMessage().'</b> ไม่ใช่ที่อยู่อีเมลที่ถูกต้อง
return $errorMsg;
}
}
$email = "someone@example.com";
try
 {
 //check if 
 if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
  {
  //ทิ้งข้อผิดพลาดถ้าอีเมล์ไม่ถูกต้อง
  throw new customException($email);
  }
 //ตรวจสอบว่ามี "example" ในที่อยู่อีเมล์หรือไม่
 if(strpos($email, "example") !== FALSE)
  {
  throw new Exception("$email is an example e-mail");
  }
 }
catch (customException $e)
 {
 echo $e->errorMessage();
 }
catch(Exception $e)
 {
 echo $e->getMessage();
 }
?>

ตัวอย่างอธิบาย:

รหัสบทด้วยสองเงื่อนไขดังกล่าว ถ้าไม่มีเงื่อนไขใดที่เป็นจริง จะทิ้งข้อผิดพลาด

  1. คลาส customException ถูกสร้างขึ้นเพื่อขยายคลาส exception อันเดิม ดังนั้นมีการสืบทอดและใช้รูปแบบและวิธีทั้งหมดของคลาสเดิม
  2. สร้างฟังก์ชัน errorMessage() ถ้าที่อยู่อีเมล์ไม่ถูกต้อง ฟังก์ชันนี้จะกลับค่าข้อความข้อผิดพลาด
  3. ปฏิบัติบล็อค "try" ไม่มีการทิ้งข้อผิดพลาดในชนิดแรก
  4. เนื่องจากอีเมลมีข้อความ "example" ตัวที่สองจะกระตุ้นข้อผิดพลาด
  5. บล็อค "catch" จะจับกุมข้อผิดพลาดและแสดงข้อความข้อผิดพลาดที่เหมาะสม

ถ้าไม่ได้จับกุม customException แต่จับกุม base exception แล้ว ให้จัดการข้อผิดพลาดในที่นั้น

ทิ้งข้อผิดพลาดอีกครั้ง

บางครั้ง เมื่อมีการทקלงข้อผิดพลาดขึ้น คุณอาจต้องการที่จะจัดการกับมันในวิธีที่ต่างจากมาตรฐาน คุณสามารถทิ้งข้อผิดพลาดอีกครั้งในบล็อค "catch" ได้

สคริปต์ควรปิดกั้นข้อผิดพลาดของระบบต่อผู้ใช้ ข้อผิดพลาดของระบบอาจสำคัญสำหรับพัฒนากร แต่ผู้ใช้ไม่ได้มีความสนใจกับมัน ในการที่จะทำให้ผู้ใช้งานง่ายต่อใช้งาน คุณสามารถทิ้งข้อผิดพลาดที่มีข้อความที่มีประโยชน์ต่อผู้ใช้มากขึ้นอีกครั้ง

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //ข้อความข้อผิดพลาด
  $errorMsg = $this->getMessage().' is not a valid E-Mail address.';
  return $errorMsg;
  }
 }
$email = "someone@example.com";
try
 {
 try
  {
  //ตรวจสอบว่ามี "example" ในที่อยู่อีเมล์หรือไม่
  if(strpos($email, "example") !== FALSE)
   {
   //ทิ้งข้อผิดพลาดถ้าอีเมล์ไม่ถูกต้อง
   throw new Exception($email);
   }
  }
 catch(Exception $e)
  {
  //ทิ้งข้อผิดพลาดอีกครั้ง
  throw new customException($email);
  }
 }
catch (customException $e)
 {
 //แสดงข้อความข้อผิดพลาดที่กำหนด
 echo $e->errorMessage();
 }
?>

ตัวอย่างอธิบาย:

รหัสด้านบนตรวจสอบว่ามีตัวอักษร "example" ในที่อยู่อีเมล์หรือไม่ ถ้ามี จะทิ้งข้อผิดพลาดอีกครั้ง

  1. คลาส customException ถูกสร้างขึ้นเพื่อขยายคลาส exception อันเดิม ดังนั้นมีการสืบทอดและใช้รูปแบบและวิธีทั้งหมดของคลาสเดิม
  2. สร้างฟังก์ชัน errorMessage() ถ้าที่อยู่อีเมล์ไม่ถูกต้อง ฟังก์ชันนี้จะกลับค่าข้อความข้อผิดพลาด
  3. ตั้งค่าตัวแปร $email ให้เป็นที่อยู่อีเมล์ที่ถูกต้อง แต่มีตัวอักษร "example"
  4. บล็อครหัส "try" มี "try" รหัสอีกครั้ง ซึ่งทำให้เกิดข้อผิดพลาดอีกครั้ง
  5. เนื่องจากอีเมล์มีตัวอักษร "example" จึงทำให้เกิดข้อผิดพลาด
  6. "catch" จับเก็บอีกครั้งและทิ้งข้อผิดพลาด "customException"
  7. จับเก็บ "customException" และแสดงข้อความข้อผิดพลาด

ถ้าภาวะที่แยกไม่ถูกจับในโค้ดบล็อค try ของตัวเอง มันจะหา catch โค้ดบล็อคที่ระดับที่สูงกว่า

ตั้งค่าภาวะที่แยกที่ระดับที่สูงสุด

set_exception_handler() ฟังก์ชันสามารถตั้งค่าฟังก์ชันที่จะจับภาวะที่แยกที่ยังไม่ถูกจับทุกตัว

<?php
function myException($exception)
{
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>

การแสดงผลของโค้ดด้านบนควรเหมือนนี้

Exception: Uncaught Exception occurred

ในโค้ดด้านบน ไม่มีโค้ดบล็อค catch แต่มีการตั้งค่าภาวะที่แยกที่ระดับที่สูงสุด ควรใช้ฟังก์ชันนี้เพื่อจับมันภาวะที่แยกที่ยังไม่ถูกจับ

กฎของภาวะที่แยก

  • โค้ดที่ต้องการทำการจัดการภาวะที่แยกต้องถูกจัดให้ใช้โค้ดบล็อค try ซึ่งจะจับมันได้ภาวะที่แยกที่อาจเกิดขึ้น
  • แต่ละโค้ดบล็อค try หรือ throw ต้องมี catch โค้ดบล็อคที่เทียบเท่าอย่างน้อยหนึ่ง
  • การใช้ multiple catch โค้ดบล็อคสามารถจับมันได้แบบฉบับต่าง ๆ
  • สามารถทิศทายภาวะในบล็อคเขียนความตั้งแต่ต้นที่มี catch โค้ดบล็อค

ย่อยๆ: ถ้ามีการทิศทายภาวะที่แยกของแก้ไขลง ต้องจับมันได้