Rumah > pembangunan bahagian belakang > PHP7 > PHP7如何使用set_error_handler和set_exception_handler处理异常机制

PHP7如何使用set_error_handler和set_exception_handler处理异常机制

醉折花枝作酒筹
Lepaskan: 2023-02-17 22:52:02
ke hadapan
2508 orang telah melayarinya

本篇文章给大家介绍一下PHP7使用set_error_handler和set_exception_handler处理异常机制的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

PHP7如何使用set_error_handler和set_exception_handler处理异常机制

由于历史原因,php一开始被设计为一门面向过程的语言,所以异常处理没有使用像Java一样的 try / catch 机制,出错时直接显示到页面上,或者记录到web服务器的错误日志中,并且php的错误分成了很多的级别,例如E_ERROR、E_WARNING、E_PARSE、E_NOTICE等等,对于像E_ERROR、E_PARSE这样的严重错误,php会直接终止脚本的运行。

虽然对于php5版本,我们可以使用set_error_handler来注册自己的错误处理方法来代替php的标准错误处理方式(输出到页面或者记录到日志),但是一些严重错误是无法通过这种方式来处理的,具体我们来看手册对该方法的介绍:

mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

设置一个用户的函数(error_handler)来处理脚本中出现的错误。 

本函数可以用你自己定义的方式来处理运行中的错误, 例如,在应用程序中严重错误发生时,或者在特定条件下触发了一个错误(使用 trigger_error()),你需要对数据/文件做清理回收。 

重要的是要记住 error_types 里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE。 error_reporting() 设置将不会起到作用而你的错误处理函数继续会被调用 —— 不过你仍然可以获取 error_reporting 的当前值,并做适当处理。 需要特别注意的是带 @ error-control operator 前缀的语句发生错误时,这个值会是 0。 

同时注意,在需要时你有责任使用 die()。 如果错误处理程序返回了,脚本将会继续执行发生错误的后一行。 

以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。
Salin selepas log masuk

手册上说的很清楚,对于E_ERROR、E_PARSE之类的错误并不能被用户处理,我们来看代码演示(以下示例用php5.6运行)

<?php
 
//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}
 
set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误
 
 
echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误
Salin selepas log masuk

运行结果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 16
Salin selepas log masuk

这时错误信息并没有像往常一样直接输出到页面上,而是按照我们自己的方式来处理了,如果不使用set_error_handler函数,错误信息会是常见的这样展示,当然我们可以关闭掉php的错误显示,这样错误就不会直接显示到页面上了。

Notice: Undefined variable: foo in D:\project\demo\demo.php on line 15
Salin selepas log masuk

这样的处理机制看似也还不错,但上面提到不是所有错误都可以这样处理,修改一下上面的代码如下:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
Salin selepas log masuk

再来运行:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 15
错误编号errno: 256
错误信息errstr: 人为产生触发一个错误
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 17

Fatal error: Call to undefined function foobar() in D:\project\demo\demo.php on line 19
Salin selepas log masuk

正如我们所料,前两个错误被我们“捕获”处理了,而最后的Fatal error并没有按照我们注册的错误函数来处理,还是使用的默认的处理方式,这也是php5版本的错误处理的一大缺陷。PHP7之后的异常处理方式有了一些新的变化,来看看手册上的介绍:

PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。 

这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。 

Error 类并非继承自 Exception 类,所以不能用 catch (Exception $e) { ... } 来捕获 Error。你可以用 catch (Error $e) { ... },或者通过注册异常处理函数( set_exception_handler())来捕获 Error。
Salin selepas log masuk

php7的这种错误处理机制有像java学习的意味,这样使得我们可以自己来处理大多数的异常,下面看代码示例(以下代码使用php7运行)

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为产生触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
catch (Error $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}
Salin selepas log masuk

运行结果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为产生触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19
Error code: 0
Error message: Call to undefined function foobar()
Error file: E:\project\demo\demo.php
Error fileline: 21
Salin selepas log masuk

这样不同类型的错误都可以被我们自己处理了,包括致命错误。如果不使用 try / catch , php7的报错信息和php5还是有一些不同:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19

Fatal error: Uncaught Error: Call to undefined function foobar() in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21
Salin selepas log masuk

致命错误的描述变成: 抛出的一个Error没有被捕获。

注意这里的catch限定的只能捕获Error类的错误,并且手册上明确说了 Error类并不是Exception类的子类,那我同时想捕获代码中的Exception错误不是做不到了吗,请看代码:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch

    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
catch (Error $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}
Salin selepas log masuk

运行结果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19

Fatal error: Uncaught Exception: This is a exception in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21
Salin selepas log masuk

那有没有什么办法呢,其实看手册上的继承关系图


可以看出,Error类和Exception类都是Throwable的子类(实际上是Error类和Exception类都实现了Throwable接口),所以上面的代码可以优化为:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    if (mt_rand(1, 10) > 5)
    {
        throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch
    }
    else
    {
        foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
    }
}
catch (Throwable $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}
Salin selepas log masuk

多次运行可以看到,不管是Exception异常还是Error异常,都可以被捕获处理了。

如果不想所有的错误都用 try / catch 处理,还可以使用set_exception_handler注册异常处理函数,这样当有未被catch的异常产生时,系统会为我们自动调用注册的处理函数来处理。

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误

function _exception_handler(Throwable $e)
{
    if ($e instanceof Error)
    {
        echo "catch Error: " . $e->getCode() . &#39;   &#39; . $e->getMessage() . &#39;<br>&#39;;
    }
    else
    {
        echo "catch Exception: " . $e->getCode() . &#39;   &#39; . $e->getMessage() . &#39;<br>&#39;;
    }
}

set_exception_handler(&#39;_exception_handler&#39;);    // 注册异常处理方法来捕获异常


echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

if (mt_rand(1, 10) > 5)
{
    throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch
}
else
{
    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
Salin selepas log masuk
错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 29
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 31
catch Error: 0 Call to undefined function foobar()


错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 29
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 31
catch Exception: 400 This is a exception
Salin selepas log masuk

这时我们可能又会被PHP7弄晕,哪些被set_error_handler处理,哪些被set_exception_handler处理,手册上也没有明确说明这块,根据我的总结,大致上不会导致脚本终止运行的错误会被set_error_handler处理,而会终止脚本运行的严重错误会被当作Error抛出,但不是绝对,上面人为触发的

E_USER_ERROR就是一个会打断脚本运行的错误,但是并没有当作Error异常抛出,而是交由set_error_handler注册的方法处理,这可能是因为这类错误是我们自己人为产生的有关,所以PHP7的错误处理还是有一些含糊不清,对于我们自己处理时要多加小心。

推荐学习:php视频教程

Atas ialah kandungan terperinci PHP7如何使用set_error_handler和set_exception_handler处理异常机制. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan