跟踪错误行和文件 nr 的正确方法。在使用自定义错误处理方法的自定义函数中使用 debug_backtrace()
Proper way of tracing error line and file nr. with debug_backtrace() in custom function that uses custom error handle method
我制作的自定义错误处理程序(见下文)运行良好。我添加了用于打印和记录错误的方法 add()。基本上它处理所有 PHP 注册错误。
我尝试在 class 之外添加 add_error() 函数,以便开发人员更友好地使用添加错误。
我遇到的问题是,我想从中获取正确的行和文件,但是使用 debug_backtrace() 似乎太复杂了。我的意思是..它确实有效,但是它 returns 数组包含其他不必要的东西,我尝试过滤数组,到 return 文件和调用错误的行,但没有运气。
如果我调用 $error->add('test','test') 例如来自 load.php 文件,其中包含 class 文件 error-handle.php , 它 returns
C:\WebServer\www\projects\backend-framework\includes\error-handle.php:144:
array (size=2)
0 =>
array (size=7)
'file' => string 'C:\WebServer\www\projects\backend-framework\load.php' (length=52)
'line' => int 34
'function' => string 'add' (length=3)
'class' => string 'ErrorHandle' (length=11)
'object' =>
object(ErrorHandle)[1]
public 'count' => int 0
public 'last_error' => null
public 'errors' =>
array (size=0)
...
public 'debug' => int 1
public 'report_errors' => int 1
public 'log_errors' => int 1
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 => string 'test' (length=5)
1 => string 'test' (length=5)
1 =>
array (size=4)
'file' => string 'C:\WebServer\www\projects\backend-framework\index.php' (length=53)
'line' => int 2
'args' =>
array (size=1)
0 => string 'C:\WebServer\www\projects\backend-framework\load.php' (length=52)
'function' => string 'require_once' (length=12)
test: test in C:\WebServer\www\projects\backend-framework\index.php on line 2
如你所见 returns index.php 而不是 load.php
基本上,每当我调用 add_error() 或 $error->add() 时,我都需要获取正确的文件& 调用函数的行。可能通过使用 debug_backtrace() 和一些高级过滤。
对于如何获得此结果的任何指导或想法,我将不胜感激。
提前致谢!
自定义错误处理程序:
<?php
/** Custom error handle **/
class ErrorHandle {
public $count = 0;
public $last_error;
public $errors = array();
public $debug;
public $report_errors;
public $log_errors;
function __construct($debug = false, $report_errors = false, $log_errors = true){
// Set error report & log args
$this->debug = $debug;
$this->report_errors = $report_errors;
$this->log_errors = $log_errors;
// Setup error reporting & logging
$this->report_errors($this->report_errors);
$this->log_errors($this->log_errors);
// Register error handle
set_error_handler(array($this, 'error_handler'));
// Register fatal error handle
register_shutdown_function(array($this, 'fatal_error_handler'));
}
function error_handler($type, $message, $file, $line){
$html_message = '';
switch ($type) {
case E_ERROR:
$error_type = 'Runtime Error';
break;
case E_WARNING:
$error_type = 'Runtime Warning';
break;
case E_PARSE:
$error_type = 'Runtime Parse';
break;
case E_NOTICE:
$error_type = 'Runtime Notice';
break;
case E_CORE_ERROR:
$error_type = 'Core Error';
break;
case E_CORE_WARNING:
$error_type = 'Core Warning';
break;
case E_COMPILE_ERROR:
$error_type = 'Compile Error';
break;
case E_COMPILE_WARNING:
$error_type = 'Compile Warning';
break;
case E_USER_ERROR:
$error_type = 'User Error';
break;
case E_USER_WARNING:
$error_type = 'User Warning';
break;
case E_USER_NOTICE:
$error_type = 'User Notice';
break;
case E_STRICT:
$error_type = 'PHP Suggestion';
break;
case E_RECOVERABLE_ERROR:
$error_type = 'PHP Notice';
break;
case E_DEPRECATED:
$error_type = 'PHP Warning';
break;
case E_USER_DEPRECATED:
$error_type = 'PHP Deprecation';
break;
default:
$error_type = 'Unknown';
}
$this->add($error_type, $message, $file, $line);
}
// Fatal error handler
function fatal_error_handler() {
$last_error = error_get_last();
if(in_array($last_error['type'],array( E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, E_PARSE))){
$this->error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
die();
}
// Turn ON/OFF display errors
function report_errors($bool=false){
ini_set('display_startup_errors', 0);
ini_set('docref_root', 0);
ini_set('docref_ext', 0);
if($bool){
error_reporting(999999999);
ini_set('error_reporting', 999999999);
ini_set('display_errors', 1);
ini_set('report_memleaks', 1);
ini_set('track_errors', 1);
ini_set('display_startup_errors', 1);
return true;
}else{
error_reporting(0);
ini_set('error_reporting', 0);
ini_set('display_errors', 0);
return false;
}
}
function log_errors($bool){
if($this->log_errors){
ini_set("log_errors", 1);
ini_set("error_log", LOGS_DIR . 'php-error_' . date('d.m.y') . '.txt');
return true;
}
return false;
}
function add($type, $message, $file = '', $line = 0){
$html_message = '';
$backtrace = debug_backtrace();
if ($file == '') $file = $backtrace[1]['file'];
if ($line == 0) $line = $backtrace[1]['line'];
//var_dump($backtrace);
$error = array(
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line
);
if(!in_multi_array($error, $this->errors)){
$this->count++;
$this->errors[$this->count] = $error;
$this->last_error = $this->errors[$this->count];
if($this->report_errors == true) echo $type . ': <strong>' . $message . '</strong> ' . '<i>in</i> <u>' . $file . '</u> <i>on line</i> <strong>' . $line . '</strong></i></br>';
if($this->log_errors == true) error_log( $type . ': ' . $message . ' in ' . $file . ' on line ' . $line );
return true;
}
return false;
}
}
?>
As you can see it returns index.php instead of load.php
实际上 returns 两者都是,只是您在访问 $backtrace[1]['file']
时看起来您实际上想要 $backtrace[0]['file']
。
我认为 debug_backtrace
当您认为必须考虑深度时更有意义。使用以下示例作为起点:
function debug($depth) {
$trace = debug_backtrace()[$depth];
if (isset($trace['file'], $trace['line'])) {
return [$trace['file'], $trace['line']];
}
return false;
}
// check depth 0
if (list($file, $line) = debug(0)) {
// ...
}
有了这个,您可以通过实验来了解您实际寻找的深度。当然,这完全取决于您的应用程序的组织方式,因此某些文件可能具有不同的深度。
好的,所以我做了一个小的变通。
这是 方法 来自 ErrorHandle class:
/**
* Report (print), Log error
* Use this function inside functions or methods. If you need
* need to add custom error outside - use global add_error() function.
* (This is because there is not yet a proper debug_backtrace method to use
* to return error FILE name & LINE number) properly!!!
*/
public function add($type, $message, $file = '', $line = 0){
$html_message = '';
/**
* WARNING! This is beta version
* If custom error is added, we need to backtrace it & filter the result to
* get accurate FILE name & LINE number.
*/
if($file == '' || $line == 0) :
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// Filtering - if we find something to exclude, we remove it to get closer to actual file & line nr.
foreach ($backtrace as $key => $value) {
// The filter
if((isset($value) && strpos($value['file'], 'error-handle.php')) || (isset($value['class']) && $value['class'] == 'ErrorHandle' && $value['function'] == 'add')){
array_splice($backtrace, $key, 1);
}
}
if ($file == '') $file = $backtrace[0]['file'];
if ($line == 0) $line = $backtrace[0]['line'];
endif;
$error = array(
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line
);
// Let's check if we haven't stored the same error previously, so there's no dublication
if(!in_multi_array($error, $this->errors)){
$this->count++;
$this->errors[$this->count] = $error;
$this->last_error = $this->errors[$this->count];
// Report Error Message
if($this->report_errors) echo $type . ': <strong>' . $message . '</strong> ' . '<i>in</i> <u>' . $file . '</u> <i>on line</i> <strong>' . $line . '</strong></i></br>';
// Log Error Message
if($this->log_errors) error_log( $type . ': ' . $message . ' in ' . $file . ' on line ' . $line );
return true;
}
return false;
}
在 class 之外我还创建了这个函数:
/**
* Add error
* Don't use this function inside functions or methods!!!
* If you need to add error inside function or method - use $error->add() function.
* (This is because there is not yet a proper debug_backtrace method to use
* to return error FILE name & LINE number) properly!!!
*/
function add_error($type, $message, $file = '', $line = 0){
global $error;
return $error->add($type, $message, $file, $line);
}
似乎一切正常。在不同的深度和水平上进行了尝试。
但是..唯一的问题,我找不到解决方法 - $error->add() 必须始终在函数和方法中使用,而 add_error() 外部函数(不能在函数和方法中使用)。还不确定为什么,但这是开始:)
我制作的自定义错误处理程序(见下文)运行良好。我添加了用于打印和记录错误的方法 add()。基本上它处理所有 PHP 注册错误。
我尝试在 class 之外添加 add_error() 函数,以便开发人员更友好地使用添加错误。 我遇到的问题是,我想从中获取正确的行和文件,但是使用 debug_backtrace() 似乎太复杂了。我的意思是..它确实有效,但是它 returns 数组包含其他不必要的东西,我尝试过滤数组,到 return 文件和调用错误的行,但没有运气。
如果我调用 $error->add('test','test') 例如来自 load.php 文件,其中包含 class 文件 error-handle.php , 它 returns
C:\WebServer\www\projects\backend-framework\includes\error-handle.php:144:
array (size=2)
0 =>
array (size=7)
'file' => string 'C:\WebServer\www\projects\backend-framework\load.php' (length=52)
'line' => int 34
'function' => string 'add' (length=3)
'class' => string 'ErrorHandle' (length=11)
'object' =>
object(ErrorHandle)[1]
public 'count' => int 0
public 'last_error' => null
public 'errors' =>
array (size=0)
...
public 'debug' => int 1
public 'report_errors' => int 1
public 'log_errors' => int 1
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 => string 'test' (length=5)
1 => string 'test' (length=5)
1 =>
array (size=4)
'file' => string 'C:\WebServer\www\projects\backend-framework\index.php' (length=53)
'line' => int 2
'args' =>
array (size=1)
0 => string 'C:\WebServer\www\projects\backend-framework\load.php' (length=52)
'function' => string 'require_once' (length=12)
test: test in C:\WebServer\www\projects\backend-framework\index.php on line 2
如你所见 returns index.php 而不是 load.php
基本上,每当我调用 add_error() 或 $error->add() 时,我都需要获取正确的文件& 调用函数的行。可能通过使用 debug_backtrace() 和一些高级过滤。
对于如何获得此结果的任何指导或想法,我将不胜感激。 提前致谢!
自定义错误处理程序:
<?php
/** Custom error handle **/
class ErrorHandle {
public $count = 0;
public $last_error;
public $errors = array();
public $debug;
public $report_errors;
public $log_errors;
function __construct($debug = false, $report_errors = false, $log_errors = true){
// Set error report & log args
$this->debug = $debug;
$this->report_errors = $report_errors;
$this->log_errors = $log_errors;
// Setup error reporting & logging
$this->report_errors($this->report_errors);
$this->log_errors($this->log_errors);
// Register error handle
set_error_handler(array($this, 'error_handler'));
// Register fatal error handle
register_shutdown_function(array($this, 'fatal_error_handler'));
}
function error_handler($type, $message, $file, $line){
$html_message = '';
switch ($type) {
case E_ERROR:
$error_type = 'Runtime Error';
break;
case E_WARNING:
$error_type = 'Runtime Warning';
break;
case E_PARSE:
$error_type = 'Runtime Parse';
break;
case E_NOTICE:
$error_type = 'Runtime Notice';
break;
case E_CORE_ERROR:
$error_type = 'Core Error';
break;
case E_CORE_WARNING:
$error_type = 'Core Warning';
break;
case E_COMPILE_ERROR:
$error_type = 'Compile Error';
break;
case E_COMPILE_WARNING:
$error_type = 'Compile Warning';
break;
case E_USER_ERROR:
$error_type = 'User Error';
break;
case E_USER_WARNING:
$error_type = 'User Warning';
break;
case E_USER_NOTICE:
$error_type = 'User Notice';
break;
case E_STRICT:
$error_type = 'PHP Suggestion';
break;
case E_RECOVERABLE_ERROR:
$error_type = 'PHP Notice';
break;
case E_DEPRECATED:
$error_type = 'PHP Warning';
break;
case E_USER_DEPRECATED:
$error_type = 'PHP Deprecation';
break;
default:
$error_type = 'Unknown';
}
$this->add($error_type, $message, $file, $line);
}
// Fatal error handler
function fatal_error_handler() {
$last_error = error_get_last();
if(in_array($last_error['type'],array( E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, E_PARSE))){
$this->error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
die();
}
// Turn ON/OFF display errors
function report_errors($bool=false){
ini_set('display_startup_errors', 0);
ini_set('docref_root', 0);
ini_set('docref_ext', 0);
if($bool){
error_reporting(999999999);
ini_set('error_reporting', 999999999);
ini_set('display_errors', 1);
ini_set('report_memleaks', 1);
ini_set('track_errors', 1);
ini_set('display_startup_errors', 1);
return true;
}else{
error_reporting(0);
ini_set('error_reporting', 0);
ini_set('display_errors', 0);
return false;
}
}
function log_errors($bool){
if($this->log_errors){
ini_set("log_errors", 1);
ini_set("error_log", LOGS_DIR . 'php-error_' . date('d.m.y') . '.txt');
return true;
}
return false;
}
function add($type, $message, $file = '', $line = 0){
$html_message = '';
$backtrace = debug_backtrace();
if ($file == '') $file = $backtrace[1]['file'];
if ($line == 0) $line = $backtrace[1]['line'];
//var_dump($backtrace);
$error = array(
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line
);
if(!in_multi_array($error, $this->errors)){
$this->count++;
$this->errors[$this->count] = $error;
$this->last_error = $this->errors[$this->count];
if($this->report_errors == true) echo $type . ': <strong>' . $message . '</strong> ' . '<i>in</i> <u>' . $file . '</u> <i>on line</i> <strong>' . $line . '</strong></i></br>';
if($this->log_errors == true) error_log( $type . ': ' . $message . ' in ' . $file . ' on line ' . $line );
return true;
}
return false;
}
}
?>
As you can see it returns index.php instead of load.php
实际上 returns 两者都是,只是您在访问 $backtrace[1]['file']
时看起来您实际上想要 $backtrace[0]['file']
。
我认为 debug_backtrace
当您认为必须考虑深度时更有意义。使用以下示例作为起点:
function debug($depth) {
$trace = debug_backtrace()[$depth];
if (isset($trace['file'], $trace['line'])) {
return [$trace['file'], $trace['line']];
}
return false;
}
// check depth 0
if (list($file, $line) = debug(0)) {
// ...
}
有了这个,您可以通过实验来了解您实际寻找的深度。当然,这完全取决于您的应用程序的组织方式,因此某些文件可能具有不同的深度。
好的,所以我做了一个小的变通。 这是 方法 来自 ErrorHandle class:
/**
* Report (print), Log error
* Use this function inside functions or methods. If you need
* need to add custom error outside - use global add_error() function.
* (This is because there is not yet a proper debug_backtrace method to use
* to return error FILE name & LINE number) properly!!!
*/
public function add($type, $message, $file = '', $line = 0){
$html_message = '';
/**
* WARNING! This is beta version
* If custom error is added, we need to backtrace it & filter the result to
* get accurate FILE name & LINE number.
*/
if($file == '' || $line == 0) :
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// Filtering - if we find something to exclude, we remove it to get closer to actual file & line nr.
foreach ($backtrace as $key => $value) {
// The filter
if((isset($value) && strpos($value['file'], 'error-handle.php')) || (isset($value['class']) && $value['class'] == 'ErrorHandle' && $value['function'] == 'add')){
array_splice($backtrace, $key, 1);
}
}
if ($file == '') $file = $backtrace[0]['file'];
if ($line == 0) $line = $backtrace[0]['line'];
endif;
$error = array(
'type' => $type,
'message' => $message,
'file' => $file,
'line' => $line
);
// Let's check if we haven't stored the same error previously, so there's no dublication
if(!in_multi_array($error, $this->errors)){
$this->count++;
$this->errors[$this->count] = $error;
$this->last_error = $this->errors[$this->count];
// Report Error Message
if($this->report_errors) echo $type . ': <strong>' . $message . '</strong> ' . '<i>in</i> <u>' . $file . '</u> <i>on line</i> <strong>' . $line . '</strong></i></br>';
// Log Error Message
if($this->log_errors) error_log( $type . ': ' . $message . ' in ' . $file . ' on line ' . $line );
return true;
}
return false;
}
在 class 之外我还创建了这个函数:
/**
* Add error
* Don't use this function inside functions or methods!!!
* If you need to add error inside function or method - use $error->add() function.
* (This is because there is not yet a proper debug_backtrace method to use
* to return error FILE name & LINE number) properly!!!
*/
function add_error($type, $message, $file = '', $line = 0){
global $error;
return $error->add($type, $message, $file, $line);
}
似乎一切正常。在不同的深度和水平上进行了尝试。 但是..唯一的问题,我找不到解决方法 - $error->add() 必须始终在函数和方法中使用,而 add_error() 外部函数(不能在函数和方法中使用)。还不确定为什么,但这是开始:)