PHP 注冊錯誤和異常處理機制


注冊錯誤和異常處理機制有三個PHP函數需要學習

1. register_shutdown_function('Bootstrap\Library\Frame::fatalError');

2. set_error_handler('Bootstrap\Library\Frame::appError');

3. set_exception_handler('Bootstrap\Library\Frame::appException');

1.register_shutdown_function 

定義:該函數是來注冊一個會在PHP中止時執行的函數

參數說明:

void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )  

注冊一個 callback ,它會在腳本執行完成或者 exit() 后被調用。

callback:待注冊的中止回調

parameter:可以通過傳入額外的參數來將參數傳給中止函數

PHP終止情況有三種

執行完成

<?php  
function test()  
{  
    echo '這個是中止方法test的輸出';  
}  
  
register_shutdown_function('test');  
  
echo 'before' . PHP_EOL;  

// => before  
// => 這個是中止方法test的輸出  

注意輸出的順序,等執行完成了之后才會去執行register_shutdown_function的中止方法test  

exit/die導致的中止

<?php  
function test()  
{  
    echo '這個是中止方法test的輸出';  
}  
  
register_shutdown_function('test');  
  
echo 'before' . PHP_EOL;  
exit();  
echo 'after' . PHP_EOL;  

// => before
// => 這個是中止方法test的輸出  

后面的after並沒有輸出,即exit或者是die方法導致提前中止。

發生致命錯誤中止

<?php  
function test()  
{  
    echo '這個是中止方法test的輸出';  
}  
  
register_shutdown_function('test');  
  
echo 'before' . PHP_EOL;  
  
// 這里會發生致命錯誤  
$a = new a();  
  
echo 'after' . PHP_EOL;  

// => before
// => Fatal error: Uncaught Error: Class 'a' not found in D:\laragon\www\php_book\test.php on line 12
// => Error: Class 'a' not found in D:\laragon\www\php_book\test.php on line 12  
// => Call Stack:  
// => 0.0020     360760   1. {main}() D:\laragon\www\php_book\test.php:0  
// => 這個是中止方法test的輸出

后面的after也是沒有輸出,致命錯誤導致提前中止了。

參數:第一個參數支持以數組的形式來調用類中的方法,第二個以及后面的參數都是可以當做額外的參數傳給中止方法。

<?php  
  
class Shutdown  
{  
    public function stop()  
    {  
        echo "這個是stop方法的輸出";  
    }  
}  
  
// 當PHP終止的時候(執行完成或者是遇到致命錯誤中止的時候)會調用new Shutdown的stop方法  
register_shutdown_function([new Shutdown(), 'stop']);  
  
// 將因為致命錯誤而中止  
$a = new a();  
  
// 這一句並沒有執行,也沒有輸出  
echo '必須終止';  

也可以在類中執行:

<?php  
  
class TestDemo {  
    public function __construct()  
    {  
        register_shutdown_function([$this, "f"], "hello");  
    }  
  
    public function f($str)  
    {  
        echo "class TestDemo->f():" . $str;  
    }  
}  
  
$demo = new TestDemo();  
echo 'before' . PHP_EOL;  
  
/** 
運行: 
before 
class TestDemo->f():hello 
 */  
可以多次調用 register_shutdown_function,這些被注冊的回調會按照他們注冊時的順序被依次調用。
不過注意的是,如果在第一個注冊的中止方法里面調用exit方法或者是die方法的話,那么其他注冊的中止回調也不會被調用。
代碼:
<?php  
/** 
 * 可以多次調用 register_shutdown_function,這些被注冊的回調會按照他們注冊時的順序被依次調用。 
 * 注意:如果你在f方法(第一個注冊的方法)里面調用exit方法或者是die方法的話,那么其他注冊的中止回調也不會被調用 
 */  
  
/** 
 * @param $str 
 */  
function f($str) {  
    echo $str . PHP_EOL;  
  
    // 如果下面調用exit方法或者是die方法的話,其他注冊的中止回調不會被調用  
    // exit();  
}  
  
// 注冊第一個中止回調f方法  
register_shutdown_function("f", "hello");  
  
class TestDemo {  
    public function __construct()  
    {  
        register_shutdown_function([$this, "f"], "hello");  
    }  
  
    public function f($str)  
    {  
        echo "class TestDemo->f():" . $str;  
    }  
}  
  
$demo = new TestDemo();  
echo 'before' . PHP_EOL;  
  
/** 
運行: 
before 
hello 
class TestDemo->f():hello 
 
注意:如果f方法里面調用了exit或者是die的話,那么最后的class TestDemo->f():hello不會輸出 
 */  
該函數的作用:
  • 析構函數:在PHP4的時候,由於類不支持析構函數,所以這個函數經常用來模擬實現析構函數
  • 致命錯誤的處理:使用該函數可以用來捕獲致命錯誤並且在發生致命錯誤后恢復流程處理

代碼如下:

<?php  
/** 
 * register_shutdown_function,注冊一個會在php中止時執行的函數,中止的情況包括發生致命錯誤、die之后、exit之后、執行完成之后都會調用register_shutdown_function里面的函數 
 * Created by PhpStorm. 
 * User: Administrator 
 * Date: 2017/7/15 
 * Time: 17:41 
 */  
  
class Shutdown  
{  
    public function stop()  
    {  
        echo 'Begin.' . PHP_EOL;  
        // 如果有發生錯誤(所有的錯誤,包括致命和非致命)的話,獲取最后發生的錯誤  
        if (error_get_last()) {  
            print_r(error_get_last());  
        }  
  
        // ToDo:發生致命錯誤后恢復流程處理  
  
        // 中止后面的所有處理  
        die('Stop.');  
    }  
}  
  
// 當PHP終止的時候(執行完成或者是遇到致命錯誤中止的時候)會調用new Shutdown的stop方法  
register_shutdown_function([new Shutdown(), 'stop']);  
  
// 將因為致命錯誤而中止  
$a = new a();  
  
// 這一句並沒有執行,也沒有輸出  
echo '必須終止';  
Fatal error: Uncaught Error: Class 'a' not found in D:\laragon\www\php_book\1_23_register_shutdown.php on line 31  
  
Error: Class 'a' not found in D:\laragon\www\php_book\1_23_register_shutdown.php on line 31  
  
Call Stack:  
    0.0060     362712   1. {main}() D:\laragon\www\php_book\1_23_register_shutdown.php:0  
  
Begin.  
Array  
(  
    [type] => 1  
    [message] => Uncaught Error: Class 'a' not found in D:\laragon\www\php_book\1_23_register_shutdown.php:31  
Stack trace:  
#0 {main}  
  thrown  
    [file] => D:\laragon\www\php_book\1_23_register_shutdown.php  
    [line] => 31  
)  
Stop.  

注意:PHP7中新增了Throwable異常類,這個類可以捕獲致命錯誤,即可以使用try...catch(Throwable $e)來捕獲致命錯誤,代碼如下:

<?php  
  
try {  
    // 將因為致命錯誤而中止  
    $a = new a();  
  
    // 這一句並沒有執行,也沒有輸出  
    echo 'end';  
} catch (Throwable $e) {  
    print_r($e);  
    echo $e->getMessage();  
}  

運行:

Error Object  
(  
    [message:protected] => Class 'a' not found  
    [string:Error:private] =>  
    [code:protected] => 0  
    [file:protected] => C:\laragon\www\php_book\throwable.php  
    [line:protected] => 5  
    [trace:Error:private] => Array  
        (  
        )  
  
    [previous:Error:private] =>  
    [xdebug_message] =>  
Error: Class 'a' not found in C:\laragon\www\php_book\throwable.php on line 5  
  
Call Stack:  
    0.0000     349856   1. {main}() C:\laragon\www\php_book\throwable.php:0  
  
)  
Class 'a' not found  
這樣的話,PHP7中使用Throwable來捕獲的話比使用register_shutdown_function這個函數來得更方便,也更推薦Throwable。
注意:Error類也是可以捕獲到致命錯誤,不過Error只能捕獲致命錯誤,不能捕獲異常Exception,而Throwable是可以捕獲到錯誤和異常的,所以更推薦。
 
總結:register_shutdown_function這個函數主要是用在處理致命錯誤的后續處理上(PHP7更推薦使用Throwable來處理致命錯誤),不過缺點也很明顯,只能處理致命錯誤Fatal error,其他的錯誤包括最高錯誤Parse error也是沒辦法處理的。
 

 

 

2.set_error_handler

通過 set_error_handler() 函數設置用戶自定義的錯誤處理程序,然后觸發錯誤(通過 trigger_error()):

<?php
 // 用戶定義的錯誤處理函數
 function myErrorHandler($errno, $errstr, $errfile, $errline) {
     echo "<b>Custom error:</b> [$errno] $errstr<br>";
     echo " Error on line $errline in $errfile<br>";
 }

 // 設置用戶定義的錯誤處理函數
 set_error_handler("myErrorHandler");

 $test=2;

 // 觸發錯誤
 if ($test>1) {
     trigger_error("A custom error has been triggered");
 }
 ?> 

以上代碼的輸出類似這樣:

Custom error: [1024] A custom error has been triggered
 Error on line 14 in C:\webfolder\test.php

定義和用法

set_error_handler() 函數設置用戶定義的錯誤處理函數。

注釋:如果使用該函數,會繞過標准 PHP 錯誤處理程序,同時如果必要,用戶定義錯誤程序通過 die() 終止腳本。

注釋:如果錯誤發生在腳本執行之前(比如文件上傳時),將不會調用自定義的錯誤處理程序因為它尚未在那時注冊。

語法

set_error_handler(errorhandler,E_ALL|E_STRICT);
參數 描述
errorhandler 必需。規定用戶錯誤處理函數的名稱。
E_ALL|E_STRICT 可選。規定顯示何種錯誤報告級別的用戶定義錯誤。默認是 "E_ALL"。

技術細節

返回值: 包含之前定義的錯誤處理程序的字符串。
PHP 版本: 4.0.1+
PHP 更新日志:

PHP 5.5:參數 errorhandler 現在接受 NULL

PHP 5.2: 錯誤處理程序必須返回 FALSE 來顯示 $php_errormsg。

3.set_exception_handler

設置用戶定義的異常處理函數:

<?php
// 用戶定義的異常處理函數
 function myException($exception) {
     echo "<b>Exception:</b> ", $exception->getMessage();
 }

 // 設置用戶定義的異常處理函數
 set_exception_handler("myException");

// 拋出異常
throw new Exception("Uncaught exception occurred!");
 ?> 

以上代碼的輸出類似這樣:

Exception: Uncaught exception occurred!

定義和用法

set_exception_handler() 函數設置用戶定義的異常處理函數。

腳本會在此異常處理程序被調用后停止執行。

語法

set_exception_handler(exceptionhandler);
參數 描述
exceptionhandler

必需。規定當一個未捕獲的異常發生時所調用函數的名稱。

注釋:也可以傳遞一個 NULL 值用於重置異常處理函數為默認值。

技術細節

返回值:

返回包含之前定義的異常處理程序的名稱的字符串,或者在錯誤時返回 NULL。

如果之前沒有定義一個錯誤處理程序,也會返回 NULL。

如果參數使用了 NULL,重置處理程序為默認狀態,並且會返回一個 TRUE。

PHP 版本: 5.0+
PHP 更新日志:

PHP 7.0.0:傳遞到 exception_handler 中的參數類型從 Exception 更改為 Throwable。

PHP 5.5:之前,如果傳遞 NULL,該函數返回 TRUE。從 PHP 5.5 起返回之前的處理程序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM