PHP Conference Japan 2024

ErrorException

(PHP 5 >= 5.1.0,PHP 7,PHP 8)

简介

一个错误异常。

类概要

class ErrorException extends Exception {
/* 属性 */
protected int $severity = E_ERROR;
/* 继承的属性 */
protected string $message = "";
private string $string = "";
protected int $code;
protected string $file = "";
protected int $line;
private array $trace = [];
private ?Throwable $previous = null;
/* 方法 */
public __construct(
    string $message = "",
    int $code = 0,
    int $severity = E_ERROR,
    ?string $filename = null,
    ?int $line = null,
    ?Throwable $previous = null
)
final public getSeverity(): int
/* 继承的方法 */
final public Exception::getCode(): int
final public Exception::getFile(): string
final public Exception::getLine(): int
final public Exception::getTrace(): array
}

属性

severity

异常的严重程度

示例

示例 #1 使用 set_error_handler() 将错误消息更改为 ErrorException

<?php

set_error_handler
(function (int $errno, string $errstr, string $errfile, int $errline) {
if (!(
error_reporting() & $errno)) {
// 此错误代码未包含在 error_reporting 中。
return;
}

if (
$errno === E_DEPRECATED || $errno === E_USER_DEPRECATED) {
// 不要为弃用警告抛出异常,因为新的或意外的
// 弃用会破坏应用程序。
return;
}

throw new
\ErrorException($errstr, 0, $errno, $errfile, $errline);
});

// 反序列化损坏的数据会触发警告,错误处理程序会将其转换为 ErrorException。
unserialize('broken data');

?>

上面的示例将输出类似以下内容

Fatal error: Uncaught ErrorException: unserialize(): Error at offset 0 of 11 bytes in test.php:16
Stack trace:
#0 [internal function]: {closure}(2, 'unserialize(): ...', 'test.php', 16)
#1 test.php(16): unserialize('broken data')
#2 {main}
  thrown in test.php on line 16

目录

添加注释

用户贡献的注释 5 条注释

18
randallgirard at hotmail dot com
14 年前
E_USER_WARNING、E_USER_NOTICE 和任何其他非终止错误代码在您将自定义 ERROR_HANDLER 与 ErrorException 结合并不会捕获错误时,都是无用的并且像 E_USER_ERROR(终止)一样工作。在 EXCEPTION_HANDLER 中,无法将执行返回到父作用域。

<?php

error_reporting
(E_ALL);
define('DEBUG', true);
define('LINEBREAK', "\r\n");

error::initiate('./error_backtrace.log');

try
trigger_error("First error", E_USER_NOTICE);
catch (
ErrorException $e )
print(
"Caught the error: ".$e->getMessage."<br />\r\n" );

trigger_error("This event WILL fire", E_USER_NOTICE);

trigger_error("This event will NOT fire", E_USER_NOTICE);

abstract class
error {

public static
$LIST = array();

private function
__construct() {}

public static function
initiate( $log = false ) {
set_error_handler( 'error::err_handler' );
set_exception_handler( 'error::exc_handler' );
if (
$log !== false ) {
if ( !
ini_get('log_errors') )
ini_set('log_errors', true);
if ( !
ini_get('error_log') )
ini_set('error_log', $log);
}
}

public static function
err_handler($errno, $errstr, $errfile, $errline, $errcontext) {
$l = error_reporting();
if (
$l & $errno ) {

$exit = false;
switch (
$errno ) {
case
E_USER_ERROR:
$type = 'Fatal Error';
$exit = true;
break;
case
E_USER_WARNING:
case
E_WARNING:
$type = 'Warning';
break;
case
E_USER_NOTICE:
case
E_NOTICE:
case @
E_STRICT:
$type = 'Notice';
break;
case @
E_RECOVERABLE_ERROR:
$type = 'Catchable';
break;
default:
$type = 'Unknown Error';
$exit = true;
break;
}

$exception = new \ErrorException($type.': '.$errstr, 0, $errno, $errfile, $errline);

if (
$exit ) {
exc_handler($exception);
exit();
}
else
throw
$exception;
}
return
false;
}

function
exc_handler($exception) {
$log = $exception->getMessage() . "\n" . $exception->getTraceAsString() . LINEBREAK;
if (
ini_get('log_errors') )
error_log($log, 0);
print(
"Unhandled Exception" . (DEBUG ? " - $log" : ''));
}

}
?>
18
triplepoint at gmail dot com
14 年前
如下所述,重要的是要意识到,除非被捕获,否则任何抛出的异常都会停止脚本。因此,将每个通知、警告或错误都转换为 ErrorException 将在触发无害事件(如 E_USER_NOTICE)时停止脚本。

在我看来,ErrorException 类的最佳用法类似于以下内容

<?php
function custom_error_handler($number, $string, $file, $line, $context)
{
// 确定此错误是否为 php 配置(php.ini、.htaccess 等)中启用的错误之一
$error_is_enabled = (bool)($number & ini_get('error_reporting') );

// -- 严重错误
// 抛出 ErrorException,由此上下文中可用的任何异常处理逻辑进行处理
if( in_array($number, array(E_USER_ERROR, E_RECOVERABLE_ERROR)) && $error_is_enabled ) {
throw new
ErrorException($errstr, 0, $errno, $errfile, $errline);
}

// -- 非严重错误/警告/通知
// 如果启用了错误,则记录错误,否则忽略它
else if( $error_is_enabled ) {
error_log( $string, 0 );
return
false; // 确保这最终会出现在 $php_errormsg 中(如果适用)
}
}
?>

将此函数设置为错误处理程序将导致仅对 E_USER_ERROR 和 E_RECOVERABLE_ERROR 抛出 ErrorException,而其他启用的错误类型将简单地记录到 error_log() 中。

值得再次注意的是,无论您做什么,“E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 和大多数 E_STRICT”永远不会到达您的自定义错误处理程序,因此不会转换为 ErrorException。请相应地进行规划。
7
luke at cywh dot com
15 年前
补充 chris AT cmbuckley DOT co DOT uk 关于 ErrorException 参数问题的评论

我注意到问题出在 ErrorException 类本身,而不是 Exception 类。仅使用 exception 类时,不再存在此问题。除了参数问题外,Exception 和 ErrorException 在堆栈跟踪中的唯一区别是参数从错误处理程序异常函数中省略了。我不确定这是不是故意的,但无论如何显示此信息应该不会造成任何伤害。

因此,您可以忽略此已损坏的扩展类,并创建自己的扩展类,从而完全避免此问题

<?php

header
('Content-Type: text/plain');

class
ErrorHandler extends Exception {
protected
$severity;

public function
__construct($message, $code, $severity, $filename, $lineno) {
$this->message = $message;
$this->code = $code;
$this->severity = $severity;
$this->file = $filename;
$this->line = $lineno;
}

public function
getSeverity() {
return
$this->severity;
}
}

function
exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new
ErrorHandler($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("exception_error_handler", E_ALL);

function
A() {
$foo->bar; // 故意导致错误
}

function
B($c) {
A();
}

try {
B('foobar');
} catch (
Exception $e) {
var_dump($e->getTrace());
}

?>

我唯一希望能够做的事情是删除错误处理程序函数的条目,因为它与主题无关。也许这就是他们尝试使用 ErrorException 类做的事情?无论如何,您无法更改它,因为跟踪函数是最终的,并且变量是私有的。
3
Christopher Marshall
3 年前
承接 [email protected] 提到的观点

我正在使用 PHP 7.4.0,并尝试在我的应用程序中引入错误处理、异常处理和致命异常处理。网络上很多信息现在已经过时,无法反映 PHP 7 和 8 中处理错误的新变化,这使得理解所有内容变得非常困难。

然而,我发现使用 register_shutdown_function 处理致命异常可以达到预期效果。set_exception_handler 也能完美地配合使用。问题出现在你同时使用 set_error_handler 时,并且触发了一个自定义错误(例如使用 trigger_error)——即使你使用的是 E_ERROR 或 E_USER_ERROR。

这是因为 PHP 试图在关闭之前以及 register_shutdown_function 实际介入之前处理错误。因此,如果你使用不同的方法处理异常、错误和致命异常,务必注意这一点。你需要像以前一样专门捕获错误,并从你的错误处理函数中返回,以便致命异常处理程序能够正常启动。

不客气……

<?php
/**
* 我们以与其他所有内容不同的方式处理基本错误
*/
public static function errorHandler($errStatus, $errMsg = 'Unknown error', $errFile = 'unknown', $errLine = 0)
{
/**
* 因为我们使用的是 set_error_handler,PHP 试图变得
* 智能,并在它转到
* register_shutdown_function 之前将致命错误和其他“错误”(即 trigger_error)路由到这里,所以我们需要确保这些
* 错误被正确捕获和处理
*
* @See https://php.net/manual/en/class.errorexception.php#95415
*/
if (\in_array($errStatus, [E_ERROR, E_PARSE, E_CORE_ERROR, E_USER_ERROR, E_ERROR]))
{
return;
}

/* 以任何你想要的方式处理其他所有内容 */
}
-4
Kevin
7 年前
我一直在四处搜索如何将 E_NOTICE 错误转换为异常,我认为我终于找到了一种干净的方法来做到这一点

@include "errorcausingcode.php";

$lastError = error_get_last();
if ( !empty( $lastError ) ) {
throw new TemplateRenderingException($lastError['message'], $lastError['type']);
}

基本上,如果它不是系统停止运行的东西,它可能会遇到这种情况。然后你可以抛出任何你想要的异常。当然,只有在你需要的时候才这样做。我需要,因为我想在出现跳过输出缓冲区的错误时清理我的输出缓冲区。
To Top