경고를 시도 / 잡을 수 있습니까?


358

일부 PHP 기본 함수에서 발생하는 경고를 포착하고 처리해야합니다.

구체적으로 특별히:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )

DNS 쿼리가 실패하면 경고가 발생합니다.

trycatch경고가 예외가 아니기 때문에 / 작동하지 않습니다.

나는 이제 두 가지 옵션이 있습니다.

  1. set_error_handler 페이지의 모든 경고를 필터링하는 데 사용해야하기 때문에 과잉으로 보입니다 (이것이 사실입니까?).

  2. 이러한 경고가 화면에 표시되지 않도록 오류보고 / 표시를 조정 한 다음 반환 값을 확인하십시오. 인 경우 false호스트 이름에 대한 레코드가 없습니다.

가장 좋은 방법은 무엇입니까?


1
stackoverflow.com/questions/136899/… 는 이것에 관한 좋은 토론입니다.
Mez

아래에 삭제 된 답변이 있습니까? 소유자 또는 누군가가?
user121196


@ user121196 : 예. 소유자가
궤도에서 가벼움 경주

답변:


373

오류 처리기 설정 및 복원

한 가지 가능성은 호출하기 전에 자신의 오류 처리기를 설정하고 나중에로 이전 오류 처리기를 복원하는 것입니다 restore_error_handler().

set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();

이 아이디어를 바탕으로 오류를 기록하는 재사용 가능한 오류 처리기를 작성할 수 있습니다.

set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();

오류를 예외로 바꾸기

set_error_handler()ErrorException클래스를 사용 하여 모든 PHP 오류를 예외로 바꿀 수 있습니다 .

set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
    // 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) {
    // ...
}

자체 오류 처리기를 사용할 때 유의해야 할 사항은 error_reporting설정 을 무시하고 모든 오류 (알림, 경고 등)를 오류 처리기에 전달 한다는 것입니다 . set_error_handler()수신하려는 오류 유형을 정의하기 위해 두 번째 인수를 설정하거나 ... = error_reporting()오류 처리기 내부를 사용하여 현재 설정에 액세스 할 수 있습니다 .

경고 억제

또 다른 가능성은 @ 연산자로 호출을 억제하고 dns_get_record()나중에 반환 값을 확인하는 것 입니다. 그러나 오류 / 경고가 억제되지 않고 처리되도록 트리거되므로 이에 대해 조언 합니다.


3
함수 호출 직전에 자체 오류 처리기를 설정 한 다음 오류 검사가 완료되면 restore_error_handler를 설정하는 것이 좋습니다.
user121196

2
동시 요청이 많고 각 요청이 1.set_error_handler ()를 수행하는 경우 스레드 안전합니다. 2.doit 3.restore_error_handler?
user121196

4
감사; 도움이됩니다. (그리고 그들은 PHP가 재앙이 아니라고 말합니다.)
Aaron Miller

2
@를 사용하여 오류를 피하기 위해 +1. E_WARNING은 실제로 치명적이지 않은 오류입니다. 일반적으로 항상 오류를 적절하게 처리해야합니다. 응용 프로그램에서 set_error_handler를 사용해야하는 경우 그렇게하십시오. 일반적으로 프로덕션 환경에서 오류를 기록하고 표시를 비활성화하는 것이 좋습니다. 로그를 확인하면 개발 환경에서 변경할 위치를 확인할 수 있습니다. @ fopen / @ unlink를 본 인스턴스가 너무 많으며 개발자가 오류를 피하거나 set_error_handler를 사용하여 오류를 처리하기 위해 검사를 수행하지 않은 이유가 궁금합니다.
fyrye

5
경고를 예외로 바꾸는 것에 대한 참고 사항 : 경고는 앱을 중단시키지 않습니다. 잡히지 않은 예외가 발생합니다!
Álvaro González

149

실제로 작동하는 솔루션은 E_WARNING다음과 같이 매개 변수로 간단한 오류 처리기를 설정하는 것으로 나타났습니다 .

set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();

function warning_handler($errno, $errstr) { 
// do something
}

4
또한 callable함수 선언을 가진 문자열 대신 익명을 사용할 수 있습니다
vp_arth

고맙지 만 중요한 블록 후에 오류 처리기를 어떻게 제거 할 수 있습니까?
Yevgeniy Afanasyev

3
우수한! 바로 trow new \Exception($errstr, $errno);내부 warning_handler기능. 감사.
블라디미르 부 카낙

이것이 가장 좋은 대답입니다!
lewis4u

28

@작업자 는주의를 기울여야 합니다. 경고는 표시하지 않지만 치명적인 오류도 표시하지 않습니다. 누군가가 작성한 시스템에서 문제를 디버깅하는 데 많은 시간을 보냈으며 @mysql_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:~$ 

이번에는 왜 실패했는지 알 수 있습니다.


5

경고를 시도 / 잡으려고했지만 동시에 일반적인 경고 / 오류 로깅을 유지합니다 (예 :) /var/log/apache2/error.log. 핸들러가 리턴해야 false합니다. 그러나 "throw new ..."문은 기본적으로 실행을 중단하므로 "wrap in function"트릭을 수행해야합니다.

PHP에서 예외를 던지는 정적 방법이 있습니까

또는 간단히 말해서 :

  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();
    // ...
  }

편집 : 면밀히 검사 한 후에는 작동하지 않는 것으로 나타났습니다. " return false && throwErrorException ..."기본적으로 예외를 throw 하지 않고 오류 로그에 로그인합니다. " false &&"에서와 같이 " "부분을 제거하면 return throwErrorException ...예외가 발생하지만, error_log에 로그인하지 않습니다. 그러나이 동작은 다른 곳에 문서화되어 있지 않으므로 여전히 게시되어 있습니다.


4

아마도 경고를 완전히 없애려고 노력할 수 있지만, 가능하지 않은 경우 @ (예 : @dns_get_record (...))로 전화를 걸고 경고가 발생한 경우 알아낼 수있는 정보를 사용할 수 있습니다 또는 아닙니다.


4

이것이 유일한 해결책이 아니라면 @를 사용해서는 안됩니다. 이 경우 dns_check_record 함수를 먼저 사용하여 레코드가 있는지 확인해야합니다.


3

file_get_contents()외부 URL 호출 주위에 이러한 코드 줄을 결합하면 " 스트림을 열지 못했습니다 : 연결 시간이 초과되었습니다 " 와 같은 경고를 훨씬 더 잘 처리 할 수있었습니다 .

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

2

경우 dns_get_record()에 실패, 그것은 반환해야 FALSE당신이 경고를 억제 할 수 있도록 @하고 반환 값을 확인합니다.


0

부울 값을 반환하는지 확인한 다음 조건으로 간단히 넣을 수 있습니다. 내 고유 키로 위반을 반환하는 oci_execute (...) 에서이 문제가 발생했습니다.

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

0

폴더 구조

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");

위와 같은 파일을 스크립트 파일에 다음과 같이 포함하십시오.

index.php

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

-2

직진 작업 일 때 경고를 표시하지 않으려면 @ 만 사용하는 것이 좋습니다 (예 : $ prop = @ ($ high / ($ width-$ depth)); 0 경고로 나누기 건너 뛰기). 그러나 대부분의 경우 처리하는 것이 좋습니다.


2
이것은 @를 사용하고 싶지 않은 한 번입니다-작업을 제어 할 수 있으며 작업을 수행하기 전에 0으로 나누 었는지 여부를 확인할 수 있습니다.
Eborbob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.