תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

טיפול ב-exceptions ב-PHP

מחבר:
בתאריך:

 

טיפול ב-Exceptions היא דרך מקובלת לטיפול בשגיאות באופן אלגנטי. לדוגמה, אם נכשל הניסיון שלנו להתחבר למסד הנתונים, אנחנו יכולים לטפל בשגיאה ולהפנות למקור נתונים אחר או לספק הודעת שגיאה. במדריך זה, אדגים את הנושא דרך טיפול בשגיאה שנגרמת כשמנסים לחלק באפס. נלמד כיצד טיפול ב-exception יכול למנוע את השגיאה, ולספק, במקומה, הודעה אלגנטית ואינפורמטיבית או רישום השגיאה ל-error log.

ראשית, בוא נראה מה עלול לקרות אם מנסים לחלק באפס ללא טיפול ב-exceptions.

בתוך המערך targilim$ מקוננים מערכים נוספים שכוללים כל אחד שני מספרים. המערך רץ דרך לולאה שיוצרת אובייקטים של המחלקה Calculate, ובתוכה המתודה divide מספקת את התוצאה של חלוקת המספר הראשון בשני.

class Calculate
{
  private $num1;
  private $num2;
 
  public function __construct($num1,$num2){
    $this -> num1 = (int)$num1;
    $this -> num2 = (int)$num2;
  }
 
  public function divide(){
    return $this -> num1 / $this -> num2;
  }
}
 

$targilim = array(
    array(8,1),
    array(9,0),
    array(4,2),
    array(6,1)
 );
 
foreach($targilim as $targil => $value){
  $calculate = new Calculate($value[0],$value[1]);
  echo $calculate -> divide();
  echo "<hr />";
}

התוצאה של התרגיל, מראה מה עלולה להיות התגובה של PHP לשגיאה בקוד, דוגמת חלוקה באפס.

הודעת שגיאה של PHP לדוגמה

קיבלנו הודעת שגיאה מכוערת ביותר, שממנה אנחנו רוצים להימנע. שגיאות אחרות, או קונפיגורציה שונה של המערכת עלולים לגרום לשגיאה פטלית ולהפסקת ריצת הקוד.

 

eBook cover The essentials of Object Oriented PHP

 

כיצד לזרוק Exception?

אנחנו יכולים למנוע את השגיאה, על ידי כך שנזרוק חריגה (throw exception) באמצעות הפקודה throw new Exception() , כשבין הסוגריים מסר שאנו יכולים להציג למשתמש או לרשום ללוג. כך נראה הקוד כשאנו זורקים שגיאה:

class Calculate
{
  private $num1;
  private $num2;
 
  public function __construct($num1,$num2){
    $this -> num1 = (int)$num1;
    $this -> num2 = (int)$num2;
  }
 
  public function divide(){
    if($this -> num2 === 0 ){
      throw new Exception("Error! trying to divide by zero.");
    }
 
    return $this -> num1 / $this -> num2;
  }
}

 

קליטת ה-exception וטיפול ב-exception

אם רק נזרוק exception, לא נמנע את השגיאה. כדי למנוע את השגיאה, נחלק את הקוד לשני בלוקים. בלוק אחד שיריץ את הקוד הנורמלי נטול השגיאות והחריגים, ובלוק שני שיקלוט את השגיאות והחריגים ויטפל בהם. הבלוק שיריץ את הקוד הרגיל הוא בלוק try, והבלוק שיתפוס ויטפל בשגיאות ובחריגים הוא בלוק catch, שמשתמש במתודות של המחלקה Exception, שהיא מחלקה מובנה לטיפול בחריגים שמספק PHP. בדוגמה זו, הודעת השגיאה שזרקנו מוצגת על ידי המתודה getMessage(), שמספקת המחלקה Exception בתוך בלוק catch.

try{
  $calculate = new Calculate($value[0],$value[1]);
  echo $calculate -> divide();
  echo "<hr />";
} catch (Exception $e){
  echo "Message: " . $e -> getMessage() . "<br />";
  echo "<hr />";
}

זה הקוד המלא:

class Calculate
{
  private $num1;
  private $num2;
 
  public function __construct($num1,$num2){
    $this -> num1 = (int)$num1;
    $this -> num2 = (int)$num2;
  }
 
  public function divide(){
    if($this -> num2 === 0 ){
      throw new Exception("Error! trying to divide by zero.");
    }
 
    return $this -> num1 / $this -> num2;
  }
}
 
$targilim = array(
    array(8,1),
    array(9,0),
    array(4,2),
    array(6,1)
 );
 
foreach($targilim as $targil => $value){
 
  try{
    $calculate = new Calculate($value[0],$value[1]);
    echo $calculate -> divide();
    echo "<hr />";
 
  } catch (Exception $e){
    echo "Message: " . $e -> getMessage() . "<br />";
    echo "<hr />";
  }
}

הודות לשינוי שהכנסנו עם זריקת Exception, והודות לטיפול ב-Exception נקבל עכשיו הודעת שגיאה אלגנטית במקום השגיאה החמורה שקיבלנו ללא טיפול בחריגים. כך זה נראה:

דוגמה לשימוש ב-class exception של PHP

דבר שחשוב לשים אליו לב, והוא שעומד בלב העניין הוא שברגע שמתרחש Exception, הקוד מדלג לבצע את מה שכתוב בבלוק catch, ובדרך מדלג על הקוד הבעייתי (שהוא במקרה זה חלוקה באפס). זו דרך אלגנטית לטפל בשגיאות ובבעיות חריגות שעלולות להופיע בקוד. דרך שמונעת הודעות שגיאה כעורות או גרוע מכך מונעת טעויות פטליות שהורגות את הסקריפט.

מתודות מועילות נוספות שמספקת המחלקה Exception הן:

getFile() שמציינת את נתיב הקובץ שבו התרחשה השגיאה.

getLine() שמראה את השורה בקובץ שבו התרחשה השגיאה.

אם נרצה להוסיף את המידע הזה להודעת השגיאה שמספק לנו הטיפול ב- Exception, אנו יכולים לעשות זאת באמצעות הקוד הבא:

try{
  $calculate = new Calculate($value[0],$value[1]);
  echo $calculate -> divide();
  echo "<hr />";
} catch (Exception $e){
  echo "Message: " . $e -> getMessage() . "<br />";
  echo "File: " . $e -> getFile() . "<br />";
  echo "Line: " . $e -> getLine() . "<br />";
  echo "<hr />";
}

תוצאה לדוגמה:

המתודות השונות שמספק exception של PHP

 

כתיבת exception לקובץ log

במקרים שבהם נרצה לכתוב מידע על השגיאה לקובץ לוג ניתן לעשות זאת באמצעות הפקודה error_log(). לדוגמה:

error_log($e -> getMessage());

זה הקוד המלא שאותו כתבנו במדריך עד כה:

class Calculate
{
  private $num1;
  private $num2;
 
  public function __construct($num1,$num2){
    $this -> num1 = (int)$num1;
    $this -> num2 = (int)$num2;
  }
 
  public function divide(){
    if($this -> num2 === 0 ){
      throw new Exception("Error! trying to divide by zero.");
    }
 
    return $this -> num1 / $this -> num2;
  }
 }
 
$targilim = array(
    array(8,1),
    array(9,0),
    array(4,2),
    array(6,1)
 );
 
foreach($targilim as $targil => $value){
  try{
    $calculate = new Calculate($value[0],$value[1]);
    echo $calculate -> divide();
    echo "<hr />";
  } catch (Exception $e){
    echo "Message: " . $e -> getMessage() . "<br />";
    echo "File: " . $e -> getFile() . "<br />";
    echo "Line: " . $e -> getLine() . "<br />";
    echo "<hr />";
    error_log($e->getMessage()." File:".$e->getFile()." Line:".$e->getLine());
  }
}

 

סדר ההוצאה לפועל של exception

כש-PHP מוציא לפועל קוד שכולל exception, במידה שמתרחש ה- exception, קוד ה-exception יקדים תמיד את האירוע החריג שהוא אמור למנוע כך שהאירוע החריג לא יצא לפועל, ובמקומו יתבצע חלק הקוד שתופס את ה-exception. בדוגמת הקוד הבאה, אנחנו אומנם קוראים קודם למתודה divide מתוך המחלקה Calculate, שקוראת בתורה למתודה is_zero מתוך המחלקה Validate, שזורקת exception במקרה של חלוקה באפס, אבל במקרה שננסה לחלק באפס, הקוד יזרוק את ה-exception, במקום לבצע את המתודה divide.

השרטוט הבא יכול לסייע להבין את בקרת הזרימה בקוד:

סדר הביצוע exception של PHP

וזה הקוד:

class Validate
{
  public function is_zero($num){
    if($num === 0){
      throw new Exception("Error! trying to divide by zero.");
    }
    return false;
  }
}
 
class Calculate
{
  private $num1;
  private $num2;
 
  public function __construct($num1,$num2){
    $this -> num1 = (int)$num1;
    $this -> num2 = (int)$num2;
  }
 
  public function divide(){
      $validate = new Validate();
    $validate -> is_zero($this -> num2);
 
    return $this -> num1 / $this -> num2;
  }
}
 
$targilim = array(
    array(8,1),
    array(9,0),
    array(4,2),
    array(6,1)
   );  
foreach($targilim as $targil => $value){
  try{
    $calculate = new Calculate($value[0],$value[1]);
    echo $calculate -> divide();
    echo "<hr />";
 
  } catch (Exception $e){
    echo "Message: " . $e -> getMessage() . "<br />";
    echo "<hr />";
  }
}

התוצאה היא שה-exception מהמחלקה Validate נזרק ויוצא לפועל במקום השגיאה שאנו מנסים למנוע במחלקה Calculate.

סדר הביצוע exception של PHP

 

לסיכום

במדריך זה הצגתי שיטה לטיפול בשגיאות ובחריגים שקיימת ב-PHP, שעושה שימוש בזריקת חריגים, במידה שמתרחש אירוע חריג, ותפיסת החריגים על ידי שימוש במתודות של המחלקה Exception שמספק PHP. שימוש במבנה כזה של קוד הוא אלגנטי, קריא ומקובל, ושימוש בו מעניק לקוד בקרת זרימה טובה.

 

המדריך מבוסס על "The essentials of Object Oriented PHP" שמלמד PHP מונחה עצמים באמצעות דוגמאות ותרגילים הקליקו על התמונה כדי לרכוש את ה-eBook:

eBook cover The essentials of Object Oriented PHP

 

לכל מדריכי ה-PHP מונחה עצמים

 

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.

למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.

שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.

המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?

השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.

הוסף תגובה חדשה

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

דג למים הוא כמו ציפור ל...?