本文介紹php開源庫BooBoo,是一個處理php異常和錯誤的開源庫,通過簡單的分析代碼,我們知道了實際項目中怎么正確的設置錯誤和異常。
這是php異常系列的第二篇,第一篇地址是:
基本概念
php中的異常和錯誤是不一樣的,錯誤英文單詞是error,異常英文單詞是exception。異常一般指出現(xiàn)正常邏輯之外的情況,而錯誤是指運行時發(fā)生了不可恢復的故障,比如使用了未定義的變量,或者語法錯誤等。異常我們通過throw拋出,catch進行捕獲,而錯誤一般發(fā)生程序就會終止,我們可以通過trigger_error觸發(fā)用戶級錯誤,然后通過set_error_handler設置處理函數,下面看段代碼:
set_error_handler('errorHandler');
trigger_error("這里描述錯誤",E_USER_ERROR);
//E_USER_ERROR:該error 所特定的錯誤類型,默認是E_USER_NOTICE
function errorHandler($errno,$errstr){
//用戶的函數需要接受兩個參數:錯誤碼和描述錯誤的 string
if($errno==E_USER_ERROR){
echo "錯誤為:",$errstr.'<br>';
}
}
運行后就會通過我們設定的errorHandler輸出錯誤。
如果我們沒有設定errorHandler,而且我們是在控制臺中運行的腳本,那就會出現(xiàn)錯誤信息,
PHP Fatal error: 這里描述錯誤 in /Users/zhuanxu/workspace/php-exceptions/error.php on line 4
那我們怎么能夠在生產環(huán)境中去除這些信息呢?
在php.ini中有兩個參數與錯誤有關,一個是display_errors,另一個是error_reporting,其中display_errors控制著是否將錯誤信息輸出到控制臺,而error_reporting則控制著錯誤報告級別。
講完這些,我們下面將開始分析BooBoo,來看看實際項目中怎么處理錯誤和異常。
BooBoo介紹
此處我們通過庫BooBoo來進行學習。
BooBoo的設計原則是:如果Errors是fatal的,那就按fatal處理,如果Errors不是Fatal的,則讓程序繼續(xù)執(zhí)行。
在錯誤的處理上,我們希望能夠在實際生產中處理錯誤,但是只在開發(fā)環(huán)境中才展示出這些錯誤信息,因此BooBoo在設計上有兩個重要的概念:Handler,F(xiàn)ormatter。
- Handler做的事情就是針對錯誤執(zhí)行一個操作,可能是記錄日志,可能是發(fā)送錯誤給報警器。
- Formatter則是將錯誤變?yōu)榭砷喿x的錯誤信息。
另外當設置display_errors關閉的時候,不會執(zhí)行Formatter操作,當然BooBoo也支持你自己針對錯誤自己制定Formatter。
代碼結構:
├── Exception
│ └── NoFormattersRegisteredException.php
├── Formatter
│ ├── AbstractFormatter.php
│ ├── CommandLineFormatter.php
│ ├── FormatterInterface.php
│ ├── HtmlFormatter.php
│ ├── HtmlTableFormatter.php
│ ├── JsonFormatter.php
│ └── NullFormatter.php
├── Handler
│ ├── HandlerInterface.php
│ ├── LogHandler.php
│ └── RavenHandler.php
├── Runner.php
└── Util
├── Frame.php
├── FrameCollection.php
└── Inspector.php
頂層是Runner.php,下面是重要的兩個目錄:Formatter和Handler,還有輔助函數Util,以及異常Exception。
我們先看使用方式
安裝
$ composer require league/booboo
新建booboo.php
use League\BooBoo\Formatter\CommandLineFormatter;
use League\BooBoo\Runner;
require_once __DIR__ . "/vendor/autoload.php";
$runner = new Runner();
$runner->pushFormatter(new CommandLineFormatter());
$runner->register(); // Registers the handlers
echo $cc;
執(zhí)行后輸出:
+--------+
| NOTICE |
+--------+
Undefined variable: cc in /Users/zhuanxu/workspace/php-exceptions/booboo.php on line 12
有了使用的感性認識后,我們看看究竟發(fā)生了什么。
在League\BooBoo\Runner的構造函數中:
public function __construct(array $formatters = [], array $handlers = []);
可以設置formatters和handlers,然后在register函數中,
//==> 關閉錯誤展示,設置3個處理函數
// We want the formaters we register to handle the errors.
ini_set('display_errors', false);
set_error_handler(array($this, self::ERROR_HANDLER));
set_exception_handler(array($this, self::EXCEPTION_HANDLER));
register_shutdown_function(array($this, self::SHUTDOWN_HANDLER));
通過3個注冊函數注冊了處理的函數。當異常發(fā)生的時候,調用exceptionHandler函數
里面會挨個調用用戶注冊的handlers,如果用戶沒有關閉錯誤顯示,會通過formatters處理后直接打印出來,但是如果關閉了錯誤顯示,則會返回給瀏覽器。
此處看下register_shutdown_function函數,其注冊的函數調用條件是:
1、當頁面被用戶強制停止時
2、當程序代碼運行超時時
3、當PHP代碼執(zhí)行完成時,代碼執(zhí)行存在異常和錯誤、警告
在函數shutdownHandler中:我們關閉了拋出異常,然后判斷是否有錯誤發(fā)生,有則進行錯誤處理。
public function shutdownHandler()
{
// We can't throw exceptions in the shutdown handler.
$this->treatErrorsAsExceptions(false);
$error = error_get_last();
if ($error && $error['type'] & $this->fatalErrors) {
$this->errorHandler(
$error['type'],
$error['message'],
$error['file'],
$error['line']
);
}
}
最后我們看下錯誤處理函數,在里面我們會判斷錯誤是否是致命錯誤,如果是則進行處理,否則按照異常處理。
BooBoo庫的介紹就到這了,通過BooBoo我們能很方便的對異常和錯誤進行統(tǒng)一處理,非常方便我們平常的開發(fā),下一篇我們將再看看Whoops庫,也是一個錯誤處理的函數,再平時開發(fā)中用到的很多。
這是 php異常系列 的第二篇,你的鼓勵是我繼續(xù)寫下去的動力,期待我們共同進步。