try { // 須要進行異常處理的代碼段; throw 語句拋出異常; }catch( Exception $e ) { ... } catch( Exception $e ) { // 處理異常 } contine.....
未被捕獲的異常會報致命錯誤:Fatal error:Uncaught exception.....
php
PHP
不會主動捕獲異常,須要程序中主動拋出 (throw
)異常,才能捕獲。throw
會自動向上拋出throw
以後的語句不會執行try
後必須有catch
,不然解析錯誤Parse error
try{ $num1=3; $num2=0; if($num2==0){ throw new Exception('0不能看成除數'); echo 'this is a test';//看不到 }else{ $res=$num1/$num2; } }catch(Exception $e){ echo $e->getMessage(); }
Php
不像java
提供了不少異常類,因此不少異常都會當成錯誤。要想變錯誤爲拋出異常,須要手動throw
異常對象html
PHP內置異常如:PDOException
、SplFileObject
能夠自動拋出異常,後面的代碼能夠繼續執行。java
當異常被拋出,throw
後的代碼不會繼續執行,PHP
會嘗試查找匹配的 catch
代碼塊。若是異常沒有被捕獲,並且又沒用使用set_exception_handler()
做相應的處理的話,那麼將發生一個嚴重的錯誤(致命錯誤),而且輸出 「Uncaught Exception
」 (未捕獲異常)的錯誤消息。mysql
try
- 須要進行異常處理的代碼應該放入try
代碼塊內,以便捕獲潛在的異常。若是沒有觸發異常,則代碼將照常繼續執行。可是若是異常被觸發,會拋出一個異常
throw
- 這裏規定如何觸發異常。每個try或 throw 必須
對應至少一個 catch。使用多個catch代碼塊能夠捕獲不一樣種類的異常。
catch
- catch代碼塊會捕獲異常,並建立一個包含異常信息的對象程序員
有時,當異常被拋出時,也許但願以不一樣於標準的方式對它進行處理。能夠在一個 catch 代碼塊中再次拋出異常。注意再次拋出異常須要try{}catch{},不能直接在catch代碼塊中throw異常
。sql
腳本應該對用戶隱藏系統錯誤。對程序員來講,系統錯誤也許很重要,可是用戶對它們並不感興趣。爲了讓用戶更容易使用,您能夠再次拋出帶有對用戶比較友好的消息的異常。
簡而言之:若是拋出了異常,就必須捕獲它。數據庫
異常:程序運行與預期不太一致錯誤:觸發的是自己的錯誤segmentfault
throw
語句拋出異常,經過catch
捕獲異常,若是未捕獲會產生致命錯誤。toString
兩個函數catch
時,通常Exception
基類放在最後,基類能夠調用自定義異常類定義的方法 /** * 自定義異常類 * Class MyException */ class MyException extends Exception { public function __construct($message = "", $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); } public function __toString() { $message = "<h2>出現異常了,信息以下</h2>"; $message .= "<p>".__CLASS__."[{$this->code}]:{$this->message}</p>"; return $message; } public function test() { echo 'this is a test'; } public function stop() { exit('script end...'); } //自定義其它方法 } try{ echo '出現異常啦'; throw new MyException('測試自定義異常'); }catch (MyException $exception){ echo $exception->getMessage(); echo $exception; } //會繼續執行 echo 'continue.........';
try{ throw new MyException('測試自定義異常'); }catch (Exception $exception){ echo $exception->getMessage(); $exception->test(); } catch (MyException $exception){ echo $exception->getMessage(); }
//將錯誤用錯誤抑制符吸取,而後拋出異常 If(@!fwrite($filename,$data)) throw new exception(自定義異常) PHP_EOL #換行符
記錄錯誤日誌信息方式:緩存
(1) :file_put_contents(LOG_PATH.'error.log';, '錯誤信息'.' '.date('Y-m-d H:i:s')."\r\n", FILE_APPEND);
服務器
(2) :error_log('錯誤信息'.' '.date('Y-m-d H:i:s')."\r\n",3,LOG_PATH.'error.log');
Exception_Observer.php /** * 給觀察者定義規範 * * Interface Exception_Observer */ interface Exception_Observer { public function update(Observable_Exception $e); }
Observable_Exception.php /** * 定義觀察者 * Class Observable_Exception */ class Observable_Exception extends Exception { //保存觀察者信息 public static $_observers = array(); public static function attach(Exception_Observer $observer) { self::$_observers[] = $observer; } public function __construct($message = "", $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->notify(); } public function notify() { foreach (self::$_observers as $observer) { $observer->update($this); } } }
Logging_Exception_Observer.php /** * 記錄錯誤日誌 * Class Logging_Exception_Observer */ class Logging_Exception_Observer implements Exception_Observer { protected $_filename = __DIR__.'/error_observer.log'; public function __construct($filename = null) { if ($filename!==null && is_string($filename)){ $this->_filename = $filename; } } public function update(Observable_Exception $e) { $message = "時間:".date('Y:m:d H:i:s',time()).PHP_EOL; $message.= "信息:".$e->getMessage().PHP_EOL; $message.= "追蹤信息:".$e->getTraceAsString().PHP_EOL; $message.= "文件:".$e->getFile().PHP_EOL; $message.= "行號:".$e->getLine().PHP_EOL; error_log($message,3,$this->_filename);//寫到日誌中 } }
test.php /** *測試 */ header('content-type:text/html;charset=utf-8'); require_once 'Exception_Observer.php'; require_once 'Logging_Exception_Observer.php'; require_once 'Observable_Exception.php'; Observable_Exception::attach(new Logging_Exception_Observer()); class MyException extends Observable_Exception{ public function test() { echo 'this is a test'; } } try{ throw new MyException('出現了異常!'); }catch (MyException $exception){ echo $exception->getMessage(); }
set_error_handler
接管系統的錯誤處理函數,set_exception_handler
接管全部沒有被catch
的異常restore_exception_handler
同restore_error_handler
同樣,本質上應該說從異常/錯誤處理函數棧中彈出一個。好比有一個異常處理函數,彈出一個的話,就沒有異常處理函數,若是有異常沒有捕獲,會交由錯誤處理函數,如沒有錯誤處理函數,異常最終會有系統錯誤處理函數處理。若是設置了2個異常處理函數,彈出一個,會交由下面一個異常處理函數處理。/** * 自定義異常函數處理器 */ header('content-type:text/html;charset=utf-8'); function exceptionHandler_1($e) { echo '自定義異常處理器1<br/>函數名:'.__FUNCTION__.PHP_EOL; echo '異常信息:'.$e->getMessage(); } function exceptionHandler_2($e) { echo '自定義異常處理器2<br/>函數名:'.__FUNCTION__.PHP_EOL; echo '異常信息:'.$e->getMessage(); } set_exception_handler('exceptionHandler_1'); //set_exception_handler('exceptionHandler_2'); //恢復到上一次定義過的異常處理函數,即exceptionHandler_1 //restore_exception_handler(); //致命錯誤信息 //restore_exception_handler(); throw new Exception('測試自定義異常處理器'); //自定義異常處理器,不會向下繼續執行,由於throw以後不會再繼續執行;try{} catch{}以後,會繼續執行 //回顧:自定義錯誤處理器會繼續執行代碼,而手動拋出的錯誤信息不會繼續執行 echo 'test';
/** * 自定義異常類處理器 * Class ExceptionHandler */ class ExceptionHandler { protected $_exception; protected $_logFile = __DIR__.'/exception_handle.log'; public function __construct(Exception $e) { $this->_exception = $e; } public static function handle(Exception $e) { $self = new self($e); $self->log(); echo $self; } public function log() { error_log($this->_exception->getMessage().PHP_EOL,3,$this->_logFile); } /** * 魔術方法__toString() * 快速獲取對象的字符串信息的便捷方式,直接輸出對象引用時自動調用的方法。 * @return string */ public function __toString() { $message = <<<EOF <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>出現異常了啊啊啊啊</h1> </body> </html> EOF; return $message; } } set_exception_handler(array('ExceptionHandler','handle')); /** * try catch不會被自定義異常處理!!!! */ try{ throw new Exception('this is a test'); }catch (Exception $exception) { echo $exception->getMessage(); } throw new Exception('測試自定義的異常處理器');
異常:
自定義異常處理器不會向下繼續執行,由於throw
以後不會再繼續執行
try{} catch{}
以後,會繼續執行錯誤:
自定義錯誤處理器會繼續執行代碼,而手動拋出的錯誤信息不會繼續執行
/** * 方式一:ErrorException錯誤異常類 * @param $errno * @param $errstr * @param $errfile * @param $errline * @throws ErrorException */ function exception_error_handler($errno,$errstr,$errfile,$errline){ throw new ErrorException($errstr,0,$errno,$errfile,$errline); } set_error_handler('exception_error_handler'); try{ echo gettype(); }catch (Exception $exception){ echo $exception->getMessage(); }
/** * 方式二:自定義異常類 * Class ErrorToException */ //顯示全部的錯誤 error_reporting(-1); class ErrorToException extends Exception{ public static function handle($errno,$errstr) { throw new self($errstr,0); } } set_error_handler(array('ErrorToException','handle')); set_error_handler(array('ErrorToException','handle'),E_USER_WARNING|E_WARNING); try{ echo $test;//notice,不會被處理 echo gettype();//warning //手動觸發錯誤 trigger_error('test',E_USER_WARNING); }catch (Exception $exception){ echo $exception->getMessage(); }
header('Content-type:text/html;charset=utf-8'); class ExceptionRedirectHandler{ protected $_exception; protected $_logFile = __DIR__.'redirect.log'; public $redirect='404.html'; public function __construct(Exception $e){ $this->_exception=$e; } public static function handle(Exception $e){ $self=new self($e); $self->log(); // ob_end_clean()清除全部的輸出緩衝,最後沒有緩存的時候會產生通知級別的錯誤 while(@ob_end_clean()); header('HTTP/1.1 307 Temporary Redirect'); //臨時重定向 header('Cache-Control:no-cache,must-revalidate');//no-cache強制向源服務器再次驗證,must-revalidate可緩存但必須再向源服務器進行確認 header('Expires: Sat, 28 Mar 2016 13:28:48 GMT'); //資源失效的時間 header('Location:'.$self->redirect); //跳轉 } public function log(){ error_log($this->_exception->getMessage().PHP_EOL,3,$this->_logFile); } } set_exception_handler(array('ExceptionRedirectHandler','handle')); $link=@mysqli_connect('127.0.0.1','root','1234561'); if(!$link){ throw new Exception('數據庫鏈接出錯啦'); }
完!