2014-12-01 4 views
1

모든 것을 포함하는 오류 처리 구현에 대한 많은 시도를 발견했으며 필자가 생각한 완벽한 솔루션을 제공하기 위해 wiki 스타일을 작성할 수있을 것이라고 생각했습니다.PHP에서 모든 오류를 어떻게 잡을 수 있습니까?

질문 :

"PHP에서 한 캐치, 처리 또는 차단하는 방법 ALL 오류 유형?"

이제는 일부가 '다시 작성'한 것으로 간주 될 수 있지만 포괄적 인 솔루션이 제안되었음을 알 수 없습니다.

답변

2

몇 가지 PHP 오류 수준이 있습니다.이 중 일부는 별도의 오류 처리기를 설정해야하며 PHP가 발생할 수있는 모든 오류를 잡으려면 이러한 '유형'의 오류를 모두 포함해야합니다. - 시작, '런타임'및 예외.

  • 글로벌 변수의 몇
  • 초기화 방법
  • 4 '비 OOP'

    내 솔루션 (지금까지 내가 말할 수있는) 파이프 내려 오는 오류를 모든 잡으려고 오류 처리 메서드

  • 'AppendError'메서드가있는 ErrorHandler 클래스 - 오류가 출력되는 방법을 수정할 수 있습니다 (이 경우이 메서드의 일부 최소 HTML에서는 오류가 화면에 덤프됩니다.)
... 이제
// Moved this line to the bottom of the 'file' for usability - 
// I keep each of the above mentioned 'pieces' in separate files. 
//$ErrorHandler = new ErrorHandler(); 

$ErrorCallback = "HandleRuntimeError"; 
$ExceptionCallback = "HandleException"; 
$FatalCallback = "HandleFatalError"; 

$EnableReporting = true; 
$ErrorLevel = E_ALL; 

function InitializeErrors() 
{ 
    if($GLOBALS["EnableReporting"]) 
    { 
     error_reporting($GLOBALS["ErrorLevel"]); 

     if(isset($GLOBALS["ErrorCallback"]) && strlen($GLOBALS["ErrorCallback"]) > 0) 
     { 
      set_error_handler($GLOBALS["ErrorCallback"]); 

      // Prevent the PHP engine from displaying runtime errors on its own 
      ini_set('display_errors',false); 
     } 
     else 
      ini_set('display_errors',true); 

     if(isset($GLOBALS["FatalCallback"]) && strlen($GLOBALS["FatalCallback"]) > 0) 
     { 
      register_shutdown_function($GLOBALS["FatalCallback"]); 

      // Prevent the PHP engine from displaying fatal errors on its own 
      ini_set('display_startup_errors',false); 
     } 
     else 
      ini_set('display_startup_errors',true); 

     if(isset($GLOBALS['ExceptionCallback']) && strlen($GLOBALS['ExceptionCallback']) > 0) 
      set_exception_handler($GLOBALS["ExceptionCallback"]); 
    } 
    else 
    { 
     ini_set('display_errors',0); 
     ini_set('display_startup_errors',0); 
     error_reporting(0); 
    } 
} 

function HandleRuntimeError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null) 
{ 
    if(isset($GLOBALS['ErrorHandler'])) 
    { 
     // Pass errors up to the global ErrorHandler to be later inserted into 
     // final output at the appropriate time. 
     $GLOBALS['ErrorHandler']->AppendError($ErrorLevel,"Runtime Error: " . $ErrorMessage,$ErrorFile,$ErrorLine,$ErrorContext); 

     return true; 
    } 
    else 
    { 
     PrintError($ErrorLevel,$ErrorMessage,$ErrorFile,$ErrorLine,$ErrorContext); 
     return true; 
    } 
} 

function HandleException($Exception) 
{ 
    if(isset($GLOBALS['ErrorCallback'])) 
    { 
     // Parse and pass exceptions up to the standard error callback. 
     $GLOBALS['ErrorCallback']($Exception->getCode(), "Exception: " . $Exception->getMessage(), $Exception->getFile(), $Exception->getLine(), $Exception->getTrace()); 

     return true; 
    } 
    else 
    {  
     PrintError($Exception->getCode(), "Exception: " . $Exception->getMessage(), $Exception->getFile(), $Exception->getLine(), $Exception->getTrace()); 
     return true; 
    } 
} 

function HandleFatalError() 
{ 
    $Error = error_get_last(); 

    // Unset Error Type and Message implies a proper shutdown. 
    if(!isset($Error['type']) && !isset($Error['message'])) 
     exit(); 
    else if(isset($GLOBALS['ErrorCallback'])) 
    { 
     // Pass fatal errors up to the standard error callback. 
     $GLOBALS["ErrorCallback"]($Error['type'], "Fatal Error: " . $Error['message'],$Error['file'],$Error['line']); 

     return null; 
    } 
    else 
    { 
     PrintError($Error['type'], "Fatal Error: " . $Error['message'],$Error['file'],$Error['line']); 
     return null; 
    } 
} 

// In the event that our 'ErrorHandler' class is in fact the generator of the error, 
// we need a plain-Jane method that will still deliver the message. 
function PrintError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null) 
{ 
    if(class_exists("ErrorHandler")) 
     $ErrorTypeString = ErrorHandler::ErrorTypeString($ErrorLevel); 
    else 
     $ErrorTypeString = "$ErrorLevel"; 

    if(isset($ErrorContext) && !is_array($ErrorContext) && strlen($ErrorContext) > 0) 
     $ErrorContext = str_replace("#", "<br/>\r\n#", $ErrorContext); 

    $ReturnValue = ""; 
    $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">\r\n"; 

    $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>\r\n"; 

    if(isset($ErrorFile) && strlen($ErrorFile) > 0) 
     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>\r\n"; 

    if(isset($ErrorLine) && strlen($ErrorLine) > 0) 
     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>\r\n"; 

    if(isset($ErrorContext) && is_array($ErrorContext)) 
     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>\r\n"; 
    else if(isset($ErrorContext) && strlen($ErrorContext) > 0) 
     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>\r\n"; 

    $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("\r\n","<br/>\r\n",$ErrorMessage) . "</span></p>\r\n"; 

    $ReturnValue .= "</div>\r\n"; 

    echo($ReturnValue); 
} 

class ErrorHandler 
{ 
    public function AppendError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null) 
    { 
     // Perhaps evaluate the error level and respond accordingly 
     // 
     // In the event that this actually gets used, something that might 
     // determine if you're in a production environment or not, or that 
     // determines if you're an admin or not - or something - could belong here. 
     // Redirects or response messages accordingly. 
     $ErrorTypeString = ErrorHandler::ErrorTypeString($ErrorLevel); 

     if(isset($ErrorContext) && !is_array($ErrorContext) && strlen($ErrorContext) > 0) 
      $ErrorContext = str_replace("#", "<br/>\r\n#", $ErrorContext); 

     $ReturnValue = ""; 
     $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">\r\n"; 

     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>\r\n"; 

     if(isset($ErrorFile) && strlen($ErrorFile) > 0) 
      $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>\r\n"; 

     if(isset($ErrorLine) && strlen($ErrorLine) > 0) 
      $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>\r\n"; 

     if(isset($ErrorContext) && is_array($ErrorContext)) 
      $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>\r\n"; 
     else if(isset($ErrorContext) && strlen($ErrorContext) > 0) 
      $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>\r\n"; 

     $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("\r\n","<br/>\r\n",$ErrorMessage) . "</span></p>\r\n"; 

     $ReturnValue .= "</div>\r\n"; 

     echo($ReturnValue); 
    } 

    public static function ErrorTypeString($ErrorType) 
    { 
     $ReturnValue = ""; 

     switch($ErrorType) 
     { 
      default: 
       $ReturnValue = "E_UNSPECIFIED_ERROR"; 
       break; 
      case E_ERROR: // 1 // 
       $ReturnValue = 'E_ERROR'; 
       break; 
      case E_WARNING: // 2 // 
       $ReturnValue = 'E_WARNING'; 
       break; 
      case E_PARSE: // 4 // 
       $ReturnValue = 'E_PARSE'; 
       break; 
      case E_NOTICE: // 8 // 
       $ReturnValue = 'E_NOTICE'; 
       break; 
      case E_CORE_ERROR: // 16 // 
       $ReturnValue = 'E_CORE_ERROR'; 
       break; 
      case E_CORE_WARNING: // 32 // 
       $ReturnValue = 'E_CORE_WARNING'; 
       break; 
      case E_COMPILE_ERROR: // 64 // 
       $ReturnValue = 'E_COMPILE_ERROR'; 
       break; 
      case E_CORE_WARNING: // 128 // 
       $ReturnValue = 'E_COMPILE_WARNING'; 
       break; 
      case E_USER_ERROR: // 256 // 
       $ReturnValue = 'E_USER_ERROR'; 
       break; 
      case E_USER_WARNING: // 512 // 
       $ReturnValue = 'E_USER_WARNING'; 
       break; 
      case E_USER_NOTICE: // 1024 // 
       $ReturnValue = 'E_USER_NOTICE'; 
       break; 
      case E_STRICT: // 2048 // 
       $ReturnValue = 'E_STRICT'; 
       break; 
      case E_RECOVERABLE_ERROR: // 4096 // 
       $ReturnValue = 'E_RECOVERABLE_ERROR'; 
       break; 
      case E_DEPRECATED: // 8192 // 
       $ReturnValue = 'E_DEPRECATED'; 
       break; 
      case E_USER_DEPRECATED: // 16384 // 
       $ReturnValue = 'E_USER_DEPRECATED'; 
       break; 
     } 

     return $ReturnValue; 
    } 
} 

$ErrorHandler = new ErrorHandler(); 

- 비켜 코드 ...

이를 구현하려면이 파일을 포함하고 'InitializeErrors'방법을 실행하는 것만 큼 간단합니다. 이 외에도 오류로 수행 할 작업은 사용자에게 달려 있습니다. 이것은 PHP가 생성 할 수있는 모든 에러에 대한 래퍼 일뿐입니다. 그리고 주어진 에러 처리 방법을 변경하기 위해 기본적으로 'AppendError'메소드에서이를 평가하고 이에 따라 응답하는 것처럼 간단합니다.

- 설명해야 할 이유 때문에 반환 값을 구현 했으므로 해당 프런트에서 내 자신의 작업을 검토해야합니다.하지만 결과에 아무런 영향이없는 것은 아닙니다.

2

오류 핸들러 세 종류의 당신이 필요가 있습니다

  • set_exception_handler은, 어떤 그렇지 않으면 캐치되지 않는 예외를 포착 할 수 있습니다.

  • set_error_handler "표준"PHP 오류를 포착 할 수 있습니다. 먼저 처리해야하거나 무시해야하는 오류인지 확인하기 위해 error_reporting과 비교해보고 싶습니다. (일반적으로 통지를 무시합니다. 아마도 나쁜 것이지만 그건 나의 선택입니다.) ErrorException을 던져서 예외 처리기가 출력을 위해 catch하도록합니다.

  • register_shutdown_functionerror_get_last을 조합 한 것. ['type']의 값을 확인하여 E_ERROR, E_PARSE 또는 catch하려는 치명적인 오류 유형인지 확인하십시오. 이것들은 보통 set_error_handler을 우회합니다. 그래서 여기에 붙잡아두면 잡을 수 있습니다.다시 말하지만, 나는 단지 ErrorException을 던지기 때문에 모든 오류는 동일한 예외 처리기로 처리됩니다.

구현 방법은 전적으로 코드 설정 방법에 따라 다릅니다. 나는 일반적으로 출력을 제거하기 위해 ob_end_clean()을 수행하고 오류가보고되었다는 좋은 오류 페이지를 제시합니다.

+0

내가 생각하는 '질문'에 대한 유효한 답변 - 그러나 기록을 위해 여기의 아이디어는 실제 구현 예를 제공하는 것이 었습니다. 상관없이 환호; 모든 좋은 정보. – DigitalJedi805

관련 문제