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 起返回之前的处理程序。

 

posted @ 2018-06-08 13:49  jiangxiaobo  阅读(1835)  评论(0编辑  收藏  举报