Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 我能试着/抓住一个警告吗?_Php_Error Handling_Try Catch - Fatal编程技术网

Php 我能试着/抓住一个警告吗?

Php 我能试着/抓住一个警告吗?,php,error-handling,try-catch,Php,Error Handling,Try Catch,我需要捕捉一些php本机函数抛出的警告,然后处理它们 具体而言: array dns_get_record ( string $hostname [, int $type= DNS_ANY [, array &$authns [, array &$addtl ]]] ) 当DNS查询失败时,它会抛出警告 try/catch不起作用,因为警告不是例外 我现在有两个选择: set\u error\u handler似乎有些过分,因为我必须使用它来过滤页面中的每个警告(这是

我需要捕捉一些php本机函数抛出的警告,然后处理它们

具体而言:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )
当DNS查询失败时,它会抛出警告

try
/
catch
不起作用,因为警告不是例外

我现在有两个选择:

  • set\u error\u handler
    似乎有些过分,因为我必须使用它来过滤页面中的每个警告(这是真的吗?)

  • 调整错误报告/显示,使这些警告不会回显到屏幕上,然后检查返回值;如果为
    false
    ,则找不到主机名的记录


  • 这里的最佳做法是什么?

    您可能应该尝试完全消除警告,但如果不可能,您可以使用@(即@dns_get_record(…))预先结束调用,然后使用您可以获得的任何信息来确定警告是否发生。

    设置并还原错误处理程序

    一种可能是在调用之前设置您自己的错误处理程序,然后使用
    restore\u error\u handler()
    还原以前的错误处理程序

    您可以基于这个想法编写一个可重用的错误处理程序,为您记录错误

    set_error_handler([$logger, 'onSilencedError']);
    dns_get_record();
    restore_error_handler();
    
    将错误转化为异常

    您可以使用
    set\u error\u handler()
    ErrorException
    类将所有php错误转换为异常

    set_error_handler(function($errno, $errstr, $errfile, $errline) {
        // error was suppressed with the @-operator
        if (0 === error_reporting()) {
            return false;
        }
        
        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
    });
    
    try {
        dns_get_record();
    } catch (ErrorException $e) {
        // ...
    }
    
    使用自己的错误处理程序时需要注意的一点是,它将绕过
    错误报告设置
    并将所有错误(通知、警告等)传递给错误处理程序。您可以在
    set\u error\u handler()
    上设置第二个参数,以定义要接收的错误类型,或使用
    …=错误处理程序中的错误报告()

    抑制警告


    另一种可能是使用@operator抑制调用,然后检查
    dns\u get\u record()
    的返回值但我建议不要这样做,因为错误/警告是被触发来处理的,而不是被抑制的。

    如果
    dns\u get\u record()
    失败,它应该返回
    FALSE
    ,因此,您可以使用
    @
    抑制警告,然后检查返回值。

    通常,您不应该使用@,除非这是唯一的解决方案。在这种特定情况下,应首先使用函数dns_check_record来了解该记录是否存在。

    请小心
    @
    操作员
    -在抑制警告的同时,也会抑制致命错误。我花了很多时间在一个系统中调试一个问题,在这个系统中有人编写了
    @mysql\u query(“…”)
    ,问题是没有将mysql支持加载到PHP中,它抛出了一个无声的致命错误。它对于PHP核心的一部分是安全的,但是请小心使用

    bob@mypc:~$ php -a
    Interactive shell
    
    php > echo @something(); // this will just silently die...
    
    没有进一步的输出-祝您调试成功

    bob@mypc:~$ php -a
    Interactive shell
    
    php > echo something(); // lets try it again but don't suppress the error
    PHP Fatal error:  Call to undefined function something() in php shell code on line 1
    PHP Stack trace:
    PHP   1. {main}() php shell code:0
    bob@mypc:~$ 
    

    这次我们可以看到它失败的原因。

    真正有效的解决方案是使用
    E\u WARNING
    参数设置简单的错误处理程序,如下所示:

    set_error_handler("warning_handler", E_WARNING);
    dns_get_record(...)
    restore_error_handler();
    
    function warning_handler($errno, $errstr) { 
    // do something
    }
    

    我想尝试/捕获一个警告,但同时保留通常的警告/错误日志记录(例如在
    /var/log/apache2/error.log
    );处理程序必须为其返回
    false
    。但是,由于“throw new…”语句基本上会中断执行,因此必须执行“wrap in function”技巧,也在以下部分中讨论:

    或者,简而言之:

      function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
      }
      function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
        return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
        # error_log("AAA"); # will never run after throw
        /* Do execute PHP internal error handler */
        # return false; # will never run after throw
      }
      ...
      set_error_handler('warning_handler', E_WARNING);
      ...
      try {
        mkdir($path, 0777, true);
      } catch (Exception $e) {
        echo $e->getMessage();
        // ...
      }
    


    编辑:仔细检查后,发现它不起作用:“
    返回false&&throwErrorException…
    ”基本上不会抛出异常,只会记录错误日志;删除“
    false&&
    ”部分,如“
    返回抛出者异常…
    ”,将使异常抛出工作正常,但随后不会登录错误日志。。。尽管如此,我仍然会将此信息发布,因为我没有在其他地方看到这种行为的记录。

    我只建议在直接操作时使用@来抑制警告(例如,$prop=@($high/($width-$depth));跳过零除警告)。但是,在大多数情况下,最好处理它。

    尝试检查它是否返回一些布尔值,然后您可以简单地将其作为一个条件。我在oci_execute(…)中遇到了这种情况,它使用我的唯一密钥返回了一些冲突

    ex.
    oci_parse($res, "[oracle pl/sql]");
    if(oci_execute){
    ...do something
    }
    

    将这些代码行组合在对外部url的
    文件\u get\u contents()
    调用周围,有助于我更好地处理诸如“打开流失败:连接超时”之类的警告:

    set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
    {
        throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
    }, E_WARNING);
    try {
        $iResult = file_get_contents($sUrl);
    } catch (Exception $e) {
        $this->sErrorMsg = $e->getMessage();
    }
    restore_error_handler();
    
    此解决方案也适用于对象上下文。您可以在函数中使用它:

    public function myContentGetter($sUrl)
    {
      ... code above ...
      return $iResult;
    }
    

    文件夹结构

    index.php //Script File
    logs //Folder for log Every warning and Errors
    CustomException.php //Custom exception File
    
    CustomException.php

    /**
    * Custom error handler
    */
    function handleError($code, $description, $file = null, $line = null, $context = null) {
        $displayErrors = ini_get("display_errors");;
        $displayErrors = strtolower($displayErrors);
        if (error_reporting() === 0 || $displayErrors === "on") {
            return false;
        }
        list($error, $log) = mapErrorCode($code);
        $data = array(
            'timestamp' => date("Y-m-d H:i:s:u", time()),
            'level' => $log,
            'code' => $code,
            'type' => $error,
            'description' => $description,
            'file' => $file,
            'line' => $line,
            'context' => $context,
            'path' => $file,
            'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
        );
        $data = array_map('htmlentities',$data);
        return fileLog(json_encode($data));
    }
    
    /**
    * This method is used to write data in file
    * @param mixed $logData
    * @param string $fileName
    * @return boolean
    */
    function fileLog($logData, $fileName = ERROR_LOG_FILE) {
        $fh = fopen($fileName, 'a+');
        if (is_array($logData)) {
            $logData = print_r($logData, 1);
        }
        $status = fwrite($fh, $logData . "\n");
        fclose($fh);
    //    $file = file_get_contents($filename);
    //    $content = '[' . $file .']';
    //    file_put_contents($content); 
        return ($status) ? true : false;
    }
    
    /**
    * Map an error code into an Error word, and log location.
    *
    * @param int $code Error code to map
    * @return array Array of error word, and log location.
    */
    function mapErrorCode($code) {
        $error = $log = null;
        switch ($code) {
            case E_PARSE:
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                $error = 'Fatal Error';
                $log = LOG_ERR;
                break;
            case E_WARNING:
            case E_USER_WARNING:
            case E_COMPILE_WARNING:
            case E_RECOVERABLE_ERROR:
                $error = 'Warning';
                $log = LOG_WARNING;
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                $error = 'Notice';
                $log = LOG_NOTICE;
                break;
            case E_STRICT:
                $error = 'Strict';
                $log = LOG_NOTICE;
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                $error = 'Deprecated';
                $log = LOG_NOTICE;
                break;
            default :
                break;
        }
        return array($error, $log);
    }
    //calling custom error handler
    set_error_handler("handleError");
    
    error_reporting(E_ALL);
    ini_set('display_errors', 'off');
    define('ERROR_LOG_FILE', 'logs/app_errors.log');
    
    include_once 'CustomException.php';
    echo $a; // here undefined variable warning will be logged into logs/app_errors.log
    
    只需像这样将上述文件包含到脚本文件中

    index.php

    /**
    * Custom error handler
    */
    function handleError($code, $description, $file = null, $line = null, $context = null) {
        $displayErrors = ini_get("display_errors");;
        $displayErrors = strtolower($displayErrors);
        if (error_reporting() === 0 || $displayErrors === "on") {
            return false;
        }
        list($error, $log) = mapErrorCode($code);
        $data = array(
            'timestamp' => date("Y-m-d H:i:s:u", time()),
            'level' => $log,
            'code' => $code,
            'type' => $error,
            'description' => $description,
            'file' => $file,
            'line' => $line,
            'context' => $context,
            'path' => $file,
            'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
        );
        $data = array_map('htmlentities',$data);
        return fileLog(json_encode($data));
    }
    
    /**
    * This method is used to write data in file
    * @param mixed $logData
    * @param string $fileName
    * @return boolean
    */
    function fileLog($logData, $fileName = ERROR_LOG_FILE) {
        $fh = fopen($fileName, 'a+');
        if (is_array($logData)) {
            $logData = print_r($logData, 1);
        }
        $status = fwrite($fh, $logData . "\n");
        fclose($fh);
    //    $file = file_get_contents($filename);
    //    $content = '[' . $file .']';
    //    file_put_contents($content); 
        return ($status) ? true : false;
    }
    
    /**
    * Map an error code into an Error word, and log location.
    *
    * @param int $code Error code to map
    * @return array Array of error word, and log location.
    */
    function mapErrorCode($code) {
        $error = $log = null;
        switch ($code) {
            case E_PARSE:
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                $error = 'Fatal Error';
                $log = LOG_ERR;
                break;
            case E_WARNING:
            case E_USER_WARNING:
            case E_COMPILE_WARNING:
            case E_RECOVERABLE_ERROR:
                $error = 'Warning';
                $log = LOG_WARNING;
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                $error = 'Notice';
                $log = LOG_NOTICE;
                break;
            case E_STRICT:
                $error = 'Strict';
                $log = LOG_NOTICE;
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                $error = 'Deprecated';
                $log = LOG_NOTICE;
                break;
            default :
                break;
        }
        return array($error, $log);
    }
    //calling custom error handler
    set_error_handler("handleError");
    
    error_reporting(E_ALL);
    ini_set('display_errors', 'off');
    define('ERROR_LOG_FILE', 'logs/app_errors.log');
    
    include_once 'CustomException.php';
    echo $a; // here undefined variable warning will be logged into logs/app_errors.log
    

    这是一个很好的讨论。下面有一个答案被删除了?是所有者还是某人?另请参见:@user121196:是。是否建议在函数调用之前设置自己的错误处理程序,然后在错误检查完成后还原错误处理程序?如果有多个并发请求,并且每个请求都执行1.set_error_handler(),这是否是线程安全的。2.doit 3.restore\u error\u handler?谢谢;这很有帮助。(他们说PHP不是一场灾难。)+1是为了避免使用@来抑制错误。E_警告实际上是一个非致命错误。通常,您应该始终尝试适当地处理错误。如果您的应用程序需要使用set_error_处理程序,请这样做。通常建议记录错误并禁用在生产环境中显示错误。检查日志后,您可以看到在开发环境中进行更改的位置。我看到@fopen/@unlink的例子太多了,我想知道为什么开发人员没有执行检查以避免错误或使用set\u error\u handl处理错误