php中的異常捕獲沒有java的強大,有些情況下,需要知道某段php程序業務是否正常執行完,可以用register_shutdown_function函數來輔助實現,這篇文章主要給大家介紹了關于PHP中register_shutdown_function函數的基礎介紹與用法的相關資料,需要的朋友可以參考。
前言
最近在看《PHP核心技術與最佳實踐》,里面有使用到一個函數,register_shutdown_function,由于之前沒有用過該函數,就去查了一下資料,就覺得是個很實用的函數,所以這里寫一下這個函數的用法,下面話不多說了,來一起看看詳細的介紹吧。
1. 函數說明
定義:該函數是來注冊一個會在PHP中止時執行的函數
參數說明:
void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )
注冊一個 callback ,它會在腳本執行完成或者 exit() 后被調用。
callback:待注冊的中止回調
parameter:可以通過傳入額外的參數來將參數傳給中止函數
2. PHP中止的情況
PHP中止的情況有三種:
執行完成
exit/die導致的中止
發生致命錯誤中止
a. 第一種情況,執行完成
- <?php
- function test()
- {
- echo '這個是中止方法test的輸出';
- }
- register_shutdown_function('test');
- echo 'before' . PHP_EOL;
運行:
before
這個是中止方法test的輸出
注意:輸出的順序,等執行完成了之后才會去執行register_shutdown_function的中止方法test
b. 第二種情況,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方法導致提前中止。
c. 第三種情況,發送致命錯誤中止
- <?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也是沒有輸出,致命錯誤導致提前中止了。
3. 參數
第一個參數支持以數組的形式來調用類中的方法,第二個以及后面的參數都是可以當做額外的參數傳給中止方法。
- <?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
- */
4. 同時調用多個
可以多次調用 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不會輸出 */
5. 用處
該函數的作用:
析構函數:在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是可以捕獲到錯誤和異常的,所以更推薦。
6.巧用register_shutdown_function判斷php程序是否執行完
還有一種應用場景就是:要做一個消費隊列,因為某條有問題的數據導致致命錯誤,如果這條數據不處理掉,那么整個隊列都會導致癱瘓的狀態,這樣可以用以下方法來解決。即:如果捕獲到有問題的數據導致錯誤,則在回調函數中將這條數據處理掉就可以了。
php范例參考與解析:
- <?php
- register_shutdown_function('myFun'); //放到最上面,不然如果下面有致命錯誤,就不會調用myFun了。
- $execDone = false; //程序是否成功執行完(默認為false)
- /**
- ********************* 業務邏輯區*************************
- */
- $tas = 3;
- if($tas == 3)
- {
- new daixiaorui();
- }
- /**
- ********************* 業務邏輯結束*************************
- */
- $execDone = true; //由于程序由上至下執行,因此當執行到此后,則證明邏輯沒有出現致命的錯誤。
- function myFun()
- {
- global $execDone;
- if($execDone === false)
- {
- file_put_contents("E:/myMsg.txt", date("Y-m-d H:i:s")."---error: 程序執行出錯。/r/n", FILE_APPEND);
- /******** 以下可以做一些處理 ********/
- }
- }
總結
register_shutdown_function這個函數主要是用在處理致命錯誤的后續處理上(PHP7更推薦使用Throwable來處理致命錯誤),不過缺點也很明顯,只能處理致命錯誤Fatal error,其他的錯誤包括最高錯誤Parse error也是沒辦法處理的。
新聞熱點
疑難解答