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('损坏的数据');
?>

上面的示例将输出类似于

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

目录

添加说明

用户贡献说明 6 个说明

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。 请相应地进行计划。
8
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 类想要做的事情? 无论如何,您无法更改它,因为跟踪函数是最终的,并且变量是私有的。
2
Christopher Marshall
2 年前
从 triplepoint at gmail dot com 提出的观点出发

我正在使用 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 年前
我一直都在 Google 上搜索如何将 E_NOTICE 错误转换为异常,我认为我终于找到了一种干净的方法来做到这一点

@include "errorcausingcode.php";

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

基本上,如果它不是系统停止运行,它很可能会碰到这个。然后你可以抛出你想要的任何异常。当然,只有当你需要时才这样做。我需要,因为我想清理我的输出缓冲区,如果出现一个跳过它的错误。
-11
xianrenb at gmail dot com
11 年前
<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new
ErrorException($errstr, $errno, 0, $errfile, $errline);
}
set_error_handler("exception_error_handler");

/* 触发异常 */
strpos();
?>

请注意,在上面的示例中,ErrorException 类中的属性 $severity 对所有类型的错误都被设置为常量零。

我认为这是一个错误,并试图提交一个错误报告,但它被关闭了,因为它不是一个错误,所以我不能说上面是错误的。

让我举一个使用 $severity 不作为常量的例子
<?php
set_error_handler
(function ($errno, $errstr, $errfile, $errline) {
throw new
ErrorException($errstr, 0, $errno, $errfile, $errline);
});

class
MyClass {
public function
methodA() {
echo(
"methodA:\n");
strpos();
}

public function
methodB() {
echo(
"methodB:\n");
trigger_error("warning message form methodB", E_WARNING);
}

public function
methodC() {
echo(
"methodC:\n");
throw new
ErrorException();
}

public function
methodD() {
echo(
"methodD:\n");
throw new
ErrorException('warning message from methodD', 0,
E_WARNING);
}

public function
run($i) {
if (
$i === 0) {
$this->methodA();
} else if (
$i === 1) {
$this->methodB();
} else if (
$i === 2) {
$this->methodC();
} else {
$this->methodD();
}
}

public function
test() {
for (
$i = 0; $i < 4; ++$i) {
try {
$this->run($i);
} catch (
ErrorException $e) {
if (
$e->getSeverity() === E_ERROR) {
echo(
"E_ERROR triggered.\n");
} else if (
$e->getSeverity() === E_WARNING) {
echo(
"E_WARNING triggered.\n");
}
}
}
}
}

$myClass = new MyClass();
$myClass->test();
?>

请注意,methodC() 使用 ErrorException 类(构造函数)的默认参数。

我认为最初的意图是让 $severity 具有默认值 1,这与 E_ERROR 完全相等。

使用属性 $code 或 Exception::getCode() 与 E_* 值进行比较不能做同样的事情(如在 methodC() 中),因为 $code 的默认值为 0,Exception 类也是如此,用户可能会将 $code 用于其他目的。
To Top