PHP錯誤、異常彙總

Error

Error級別

Fatal Error:致命錯誤(腳本終止運行)

E_ERROR          致命的運行時的致命錯誤,終止程序執行
E_CORE_ERROR PHP 啓動時的致命錯誤
E_COMPILE_ERROR  PHP編譯時的致命錯誤
E_USER_ERROR     用戶產生的致命錯誤

Parse Error:編譯時的解析錯誤(腳本終止運行)

Parse Error  編譯時的語法解析錯誤

Warning Error:警告錯誤(僅給出提示信息,可是腳本不會終止運行。)

E_WARNING          運行時警告 (非致命錯誤)。
E_CORE_WARNING     PHP初始化啓動過程當中發生的警告 (非致命錯誤) 。
E_COMPILE_WARNING  編譯警告
E_USER_WARNING     用戶產生的警告信息

Notice Error:通知錯誤(僅給出通知信息,可是腳本不會終止運行。)

E_NOTICE       運行時通知。表示腳本遇到可能會表現爲錯誤的狀況.
E_USER_NOTICE  用戶產生的通知信息。

set_error_handler()捕獲錯誤【有侷限】

函數說明

set_error_handler($callback);//設置一個用戶的函數(error_handler)來處理腳本中出現的錯誤。

函數的侷限性

如下級別的錯誤不能由用戶定義的函數來處理:
E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 調用 set_error_handler() 函數所在文件中產生的大多數 E_STRICT。php

也就是:set_error_handler($callback)只能捕獲系統產生的一些Warning、Notice級別的Error。數組

使用方法

<?php
set_error_handler("error_handler");
function error_handler($errno,$errstr,$errfile,$errline){
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//獲取到錯誤能夠本身處理,好比記Log、報警等等
    echo $str;
}
echo $test;//$test未定義,會報一個notice級別的錯誤

輸出結果:閉包

"errno":8
"errstr":Undefined variable: test
"errfile":/Users/shuchao/Desktop/handler.php
"errline":13

如何捕獲PHP的Fatal Error、Parse Error等

需求描述

獲取PHP的fatal error,好比記錄到Log裏面,利於咱們分析線上問題,能夠作線上服務的監控。函數

兩個函數

register_shutdown_function()

register_shutdown_function($callback)

register_shutdown_function(),就把你要註冊進去的function放進【僞裝是隊列吧】,等到腳本正常退出或顯示調用exit時,再把註冊進去的function拉出來執行.ui

register_shutdown_function()調用的3種狀況:spa

  • 腳本正常退出時;code

  • 在腳本運行(run-time not parse-time)出錯退出時;隊列

  • 用戶調用exit方法退出時。圖片

error_get_last()

error_get_last();//函數獲取最後發生的錯誤。

該函數以數組的形式返回最後發生的錯誤。開發

返回的數組包含 4 個鍵和值:

[type] - 錯誤類型
[message] - 錯誤消息
[file] - 發生錯誤所在的文件
[line] - 發生錯誤所在的行

使用方法

<?php
register_shutdown_function( "fatal_handler" );
define('E_FATAL',  E_ERROR | E_USER_ERROR |  E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR| E_PARSE );
function fatal_handler() {
  if( $error = error_get_last()) {
    $errno   = $error["type"];
    $errfile = $error["file"];
    $errline = $error["line"];
    $errstr  = $error["message"];
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//獲取到錯誤能夠本身處理,好比記Log、報警等等
    echo $str;
  }
}

強烈注意

在parse-time出錯的時候,是不會調用register_shutdown_function()函數的。只有在run-time出錯的時候,纔會調用register_shutdown_function()。

下面咱們舉例說明:

NO.1

error_handler.php
<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
function test(){}
function test(){}

執行結果以下:

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/error_handler.php:6) in /Users/shuchao/Desktop/error_handler.php on line 7
緣由分析

在執行error_handler.php的時候,因爲重複定義了兩個函數test(),在php的parse-time就出錯了(不是run-time),因此不能回調register_shutdown_function()中的函數。

NO.2

error_handler.php
<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
if(true){
   function test(){}
}
function test(){}

執行結果以下:

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/error_handler.php:9) in /Users/shuchao/Desktop/error_handler.php on line 7
Yeah,it's worked!%
緣由分析

咱們看到,上面回調了register_shutdown_function().
由於咱們加了一個if()判斷,if()裏面的test()方法,至關於一個閉包,與外面的test()名稱不衝突。
也就是,上面的代碼在parse-time沒有出錯,而是在run-time的時候出錯了,因此咱們可以獲取到fatal error。

NO.3

error_handler.php
<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
test_error.php
<?php
include './error_handler.php';
function test(){}
function test(){}

執行 test_error.php的結果以下

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/test_error.php:3) in /Users/shuchao/Desktop/test_error.php on line 4
緣由分析

當咱們在運行test_error.php的時候,由於redeclare了兩個test()方法,因此php的語法解析器在parse-time的時候就出錯了。 因此不能回調register_shutdown_function()中的方法,不能catch住這個fatal error。

NO.4

error_handler.php
<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
test_error.php
<?php
function test(){}
function test(){}
include_all.php
require './error_handler.php';
require './test_error.php';

執行 include_all.php的結果以下

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/include_all.php:2) in /Users/shuchao/Desktop/include_all.php on line 3
Yeah,it's worked!%
結果分析

上面咱們捕獲了fatal_error.
由於在運行include_all.php的時候,include_all.php自己語法並無出錯,也就是在parse-time的時候並無出錯,而是include的文件出錯了,也就是在run-time的時候出錯了,這個時候是能回調register_shutdown_function()中的函數的。

強烈建議:若是咱們要使用register_shutdown_function進行錯誤捕捉,使用NO.4,最後一種方法,能夠確保錯誤都能捕捉到。

更優美的寫法·獲取全部錯誤

set_error_handler()與register_shutdown_function()、error_get_last()的結合使用

<?php
register_shutdown_function( "fatal_handler" );
set_error_handler("error_handler");

define('E_FATAL',  E_ERROR | E_USER_ERROR |  E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR| E_PARSE );

//獲取fatal error
function fatal_handler() {
    $error = error_get_last();
    if($error && ($error["type"]===($error["type"] & E_FATAL))) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];
        error_handler($errno,$errstr,$errfile,$errline);
  }
}
//獲取全部的error
function error_handler($errno,$errstr,$errfile,$errline){
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//獲取到錯誤能夠本身處理,好比記Log、報警等等
    echo $str;
}

Exception

Exception與Error的區別

Exception

當異常拋出的時候,咱們是想要去捕獲他,並去作處理的。
因此異常常常被當作程序的控制流程使用。

Error

Error是不可恢復的,是在開發過程當中要去解決的。

使用Exception的例子

我想執行insert語句插入一條數據,可能插入失敗(好比ID重複),注意是可能失敗,因此這是一個可能的狀況,也就是異常狀況。
咱們就能夠使用異常來處理這個問題

try {
  $row->insert();
  $inserted = true;
} catch (Exception $e) {
  echo "There was an error inserting the row - ".$e->getMessage();
  $inserted = false;
}

echo "Some more stuff";

如何catch一個未捕獲的Exception

場景描述

假設程序中的有些地方直接throw了異常,沒有進行catch。
咱們如今想要無論在程序的任何一個地方throw異常,即使在throw的地方沒有被catch,咱們也要能catch住,如何作到呢?

一個函數:set_exception_handler()

//設置默認的異常處理程序,用於沒有用 try/catch 塊來捕獲的異常。 在 exception_handler 調用後異常會停止。
set_exception_handler()

使用示例

一、exception_handler.php

<?php
set_exception_handler("my_exception");
function my_exception($exception){
    echo $exception->getMessage();
}

二、test_exception.php

<?php
require "./exception_handler.php";
throw new Exception("I am Exception");

如今咱們運行 test_exception.php,結果以下:

I am Exception //證實咱們throw的Exception被捕獲了

更多精彩,請關注公衆號「聊聊代碼」,讓咱們一塊兒聊聊「左手代碼右手詩」的事兒。
圖片描述

相關文章
相關標籤/搜索