1

我已经制作了可以正常工作的自定义错误处理程序(见下文)。我添加了用于打印和记录错误的方法add() 。基本上它处理所有 PHP 注册的错误。

我尝试在类外部添加add_error()函数,以便开发人员更友好地使用添加错误。我遇到的问题是,我想从中获取正确的行和文件,但是使用debug_backtrace()似乎太复杂了。我的意思是..它可以解决问题,但是它返回了其他不必要的东西的数组,我尝试过滤数组,以返回文件和调用错误的行,但没有运气。

例如,如果我从load.php文件中调用$error->add(' test ',' test ') ,其中包含类文件error-handle.php,它会返回

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

如您所见,它返回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;
    }

}
?>
4

2 回答 2

1

如您所见,它返回index.php而不是load.php

它实际上同时返回了两者,只是$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)) {
    // ...
}

有了这个,你可以尝试看看你真正在寻找什么深度。当然,这一切都取决于您的应用程序的组织方式,因此某些文件可能具有不同的深度。

于 2016-11-01T15:52:09.267 回答
0

好的,所以我做了一个小工作。这是来自ErrorHandle类的方法:

     /**
     * 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;
    }

在课堂之外,我还创建了这个函数:

/**
 * 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()函数在外部(不能在函数和方法中使用)。还不知道为什么,但这是开始的:)

于 2016-11-08T00:34:54.800 回答