從零開始攻略PHP(9)——錯誤和異常處理

分類:IT技術 時間:2016-10-14

1.Exception類

  這個類是PHP為異常處理提供的內置類。構造函數的兩個參數分別是錯誤消息和錯誤代碼。

  除了構造函數之外,該類還提供了如下的內置方法:

    · getCode() 返回傳遞給構造函數的代碼

    · getmessage() 返回傳遞給構造函數的消息

    · getFile() 返回產生異常的代碼文件的完整路徑

    · getLine() 返回代碼文件中產生異常的代碼行號

    · getTrace() 返回一個包含了產生異常的代碼回退路徑的數組

    · getTraceAsString() 返回與getTrace()方向相同的信息,該信息將被格式化成一個字符串。

    · _toString() 允許簡單地顯示一個Exception對象,並且給出以上所有方法可以提供的信息。

  通過執行以下命令,可以獲得相同的異常信息(以及代碼回退路徑):

echo $e;

  回退路徑顯示了在發生異常時所執行的函數。

 

2.異常控制結構

  異常處理的基本思想是代碼在try代碼塊被調用執行。在PHP中,異常必須手動拋出。

  異常控制結構:try...throw...catch

  可以將多個catch代碼塊與一個try代碼塊進行關聯。還可以在一個catch代碼塊產生新的異常。

  如下代碼拋出並捕獲一個異常:

<?php

try  {

  throw new Exception("A terrible error has occurred", 42);

}

catch (Exception $e) {

  echo "Exception ". $e->getCode(). ": ". $e->getMessage()."<br />".

  " in ". $e->getFile(). " on line ". $e->getLine(). "<br />";

}

?>

  這裏我們使用了exception類的前四個方法,catch代碼塊報告了異常錯誤信息以及發生錯誤位置的說明。

 

3.用戶自定義異常

  可以擴展Exception類來創建自己的異常類。

  可能需要繼承的代碼:

 

<?php 
class Exception{
    function __construct(string $message=NULL,int $code=0){
        if(func_num_args()){
            $this->message = $message;
        }
        $this->code = $code;
        $this->file = __FILE__;    // of throw clause
        $this->line = __LINE__; // of throw clause
        $this->trace = debug_backtrace();
        $this->string = StringFormat($this);
    }

    protected $message = "Unknown exception ";    // exception message
    protected $code = 0;    // user defined exception code
    protected $file;    // source filename of exception
    protected $line;    // source line of exception

    private $trace;    // backtrace of exception
    private $string;    // internal only!!

    final function getMessage(){
        return $this->message;
    }
    final function getCode(){
        return $this->code;
    }
    final function getFile(){
        return $this->file;
    }
    final function getTrace(){
        return $this->trace;
    }
    final function getTraceAsString(){
        return self::TraceFormat($this);
    }
    function _toString(){
        return $this->string;
    }
    static private function StringFormat(Exception $exception){
        // ... a function not available in PHP scripts
        // that returns all relevant information as a string
    }
    static private function TraceFormat(Exception $exception){
        // ... a function not available in PHP scripts
        // that returns the backtrace as a string
    }
}
?>

  該類的大多數公有方法都是final的:這就意味著不能重載這些方法。我們可以創建自己的Exception子類,但是不能改變這些基本方法的行為。請註意,_toString()函數可以重載,因此我們可以改變異常的顯示方式。也可以添加自己的方法。

  用戶自定義的Exception類示例:

 

<?php

class myException extends Exception
{
  function __toString()
  {
       return "<table border=\"1\">
       <tr>
       <td><strong>Exception ".$this->getCode()."
       </strong>: ".$this->getMessage()."<br />"."
       in ".$this->getFile()." on line ".$this->getLine()."
       </td>
       </tr>
       </table><br />";
   }
}

try
{
  throw new myException("A terrible error has occurred", 42);
}
catch (myException $m)
{
   echo $m;
}

?>

 

  在以上代碼中,我們聲明了一個新的異常類myException,該類擴展了Exception基類。該類與Exception類之間的差異在於重載了_toString()方法,從而為打印異常提供了一個更好的方法。

 

4.文件I/O相關的異常

  寫文件時可能會出現三種情況的錯誤:文件無法打開、無法獲得寫鎖或者文件無法寫入。我們為每一種可能性都創建了一個異常類:

 

<?php

class fileOpenException extends Exception
{
  function __toString()
  {
       return "fileOpenException ". $this->getCode()
              . ": ". $this->getMessage()."<br />"." in "
              . $this->getFile(). " on line ". $this->getLine()
              . "<br />";
   }
}

class fileWriteException extends Exception
{
  function __toString()
  {
       return "fileWriteException ". $this->getCode()
              . ": ". $this->getMessage()."<br />"." in "
              . $this->getFile(). " on line ". $this->getLine()
              . "<br />";
   }
}

class fileLockException extends Exception
{
  function __toString()
  {
       return "fileLockException ". $this->getCode()
              . ": ". $this->getMessage()."<br />"." in "
              . $this->getFile(). " on line ". $this->getLine()
              . "<br />";
   }
}

?>

  Exception類的這些子類並沒有執行任何特別的操作。事實上,對於這個應用程序的作用來說,可以讓它們成為空的子類或者使用PHP所提供的Exception類。然而,我們為每個子類提供了_toString()方法,從而可以解釋所發生的異常類型:

 

<?php

  require_once("file_exceptions.php");

  // create short variable names
  $tireqty = $_POST['tireqty'];
  $oilqty = $_POST['oilqty'];
  $sparkqty = $_POST['sparkqty'];
  $address = $_POST['address'];

  $DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
?>
<html>
<head>
  <title>Bob's Auto Parts - Order Results</title>
</head>
<body>
<h1>Bob's Auto Parts</h1>
<h2>Order Results</h2>
<?php
$date = date('H:i, jS F');

echo "<p>Order processed at ".$date."</p>";

echo '<p>Your order is as follows: </p>';

$totalqty = 0;
$totalqty = $tireqty + $oilqty + $sparkqty;
echo "Items ordered: ".$totalqty."<br />";

if( $totalqty == 0) {
  echo "You did not order anything on the previous page!<br />";
} else {
  if ( $tireqty > 0 ) {
    echo $tireqty." tires<br />";
  }
  if ( $oilqty > 0 ) {
    echo $oilqty." bottles of oil<br />";
  }
  if ( $sparkqty > 0 ) {
    echo $sparkqty." spark plugs<br />";
  }
}

$totalamount = 0.00;

define('TIREPRICE', 100);
define('OILPRICE', 10);
define('SPARKPRICE', 4);

$totalamount = $tireqty * TIREPRICE
             + $oilqty * OILPRICE
             + $sparkqty * SPARKPRICE;

$totalamount=number_format($totalamount, 2, '.', ' ');

echo "<p>Total of order is ".$totalamount."</p>";
echo "<p>Address to ship to is ".$address."</p>";

$outputstring = $date."\t".$tireqty." tires \t".$oilqty." oil\t"
                  .$sparkqty." spark plugs\t\$".$totalamount
                  ."\t". $address."\n";

// open file for appending
try
{
  if (!($fp = @fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'ab')))
      throw new fileOpenException();

  if (!flock($fp, LOCK_EX))
     throw new fileLockException();

  if (!fwrite($fp, $outputstring, strlen($outputstring)))
     throw new fileWriteException();
  flock($fp, LOCK_UN);
  fclose($fp);
  echo "<p>Order written.</p>";
}
catch (fileOpenException $foe)
{
   echo "<p><strong>Orders file could not be opened.
         Please contact our webmaster for help.</strong></p>";
}
catch (Exception $e)
{
   echo "<p><strong>Your order could not be processed at this time.
         Please try again later.</strong></p>";
}

?>
</body>
</html>

  可以看到,以上腳本的文件I/O部分被封裝在一個try代碼塊中。通常,良好的編碼習慣要求try代碼塊的代碼量較少,並且在代碼塊的結束處捕獲相關異常。這使得異常處理代碼更容易編寫和維護,因為可以看到所處理的內容。

  如果無法打開文件,將拋出一個fileOpenException異常;如果無法鎖定該文件,將拋出一個fileLockException異常;而如果無法寫這個文件,將拋出一個fileWriteException異常。

  我們給出了兩個catch代碼塊:一個用來處理fileOpen-Exception異常,而另一個用來處理Exception。由於其他異常都是從Exception繼承過來的,它們將被第二個catch代碼塊捕獲。catch代碼塊與每一個instanceof操作符相匹配。這就是為每一個類擴展自己異常類的理由。

  如果異常沒有匹配的catch語句塊,PHP將報告一個致命錯誤。

  請註意fopen()函數的調用仍然使用了@錯誤抑制操作符前綴。如果該函數調用失敗,PHP將發出一個警告,根據php.ini中的錯誤報告設置不同,該警告可能會被報告或者記錄。無論是否產生一個異常,這個警告仍然會發出。

  好了,從零開始攻略PHP系列到這裏就水完了,僅供參考,好多我也是一知半解,只是整理出來方便查閱。下個月會陸續發一些數據庫的,也就是該書整理的第二篇。

 

整理自《PHP and mysql Web 開發》

 


Tags: occurred 字符串 error 從零開始 信息

文章來源:


ads
ads

相關文章
ads

相關文章

ad