16. 장. Error Handling

PHP에는 다음과 같은 여러 에러와 경고 형태가 있다.:

표 16-1. PHP error types

ValueConstantDescriptionNote
1E_ERRORNormal Function Errors (일반적인 에러) 
2E_WARNINGNormal Warnings (일반적인 경고) 
4E_PARSEParser Errors (문법 에러) 
8E_NOTICE Notices (알림-무시할 수 있는 알림이지만 버그의 가능성을 가지고 있는 경우)  
16E_CORE_ERRORfatal errors that occur during PHP's initial startup (PHP가 처음 시작될 때 발생한 치명적 에러)PHP 4 only
32E_CORE_WARNINGwarnings (non fatal errors) that occur during PHP's initial startup (PHP가 처음 시작될 때 발생한 치명적이지 않은 경고)PHP 4 only
64E_COMPILE_ERRORfatal compile-time errors (컴파일시 생긴 치명적 에러)PHP 4 only
128E_COMPILE_WARNINGcompile-time warnings (non fatal errors) (컴파일시 발생한 치명적이지 않은 경고)PHP 4 only
256E_USER_ERRORuser-generated error message (사용자가 만든 에러 메세지)PHP 4 only
512E_USER_WARNINGuser-generated warning message (사용자가 만든 경고 메세지)PHP 4 only
1024E_USER_NOTICE user-generated notice message (사용자가 만든 알림 메세지)PHP 4 only
 E_ALLall of the above, as supported (지원가능한 위의 것 모두) 

위의 값(숫자, 상수 모두)은 레포트하기 원하는 내용의 비트를 설정하기 위해 조합하여 사용할 수 있다. 원하는 값을 조합해내기 위해 bitwise operators에 있는 비트 조작 연산자를 사용한다. 단 php.ini 파일에서는 '|', '~', '!', '&'의 네개의 연산자만 사용가능하고, php3.ini에서는 어떤 비트단위 연산자도 사용할 수 없다.

PHP4에서 error_reporting의 기본값은 E_ALL & ~E_NOTICE이다. 즉, 모든 에러와 경고를 출력하지만 알림(notice)는 레포팅하지 않는다. PHP3에서의 기본값은 (E_ERROR | E_WARNING | E_PARSE)이다. 내용적으로는 PHP4와 같다. PHP3의 php3.ini에서는 상수를 사용한 설정을 사용할 수 없으므로, error_reporting의 값은 반드시 숫자여야 한다. 그러므로 기본값은 7이다.

초기 설정은 ini 파일에 있는 error_reporting 지시자를 사용하여 변할 수 있고, 아파치의 httpd.conf파일에서 php_error_reporting (PHP3에서는 php3_error_reporting) 지시자를 사용하여 설정할 수도 있다. 또한, 스크립트 실행중에 error_reporting() 함수를 사용하여 설정할 수도 있다.

주의

PHP3에서 PHP4로 프로그램 코드나 서버 자체를 이전할 경우, 이 설정과 error_reporting() 함수의 호출 내역을 반드시 확인하거나, E_COMPILE_ERROR를 포함한 새로운 에러 타입에 대한 레포팅을 불가능하게 하여야 한다. 자칫하면 어떤 문제가 어디서 발생했는가에 대한 정보없이 빈 문서를 만들어 낼 수도 있으므로 주의하자.

모든 PHP 표현식(expression)은 "@"를 앞에 붙이고 호출되면 error reporting을 하지 않는다. 만약 track_errors 옵션이 Enabled로 되어 있고 해당 문장에서 에러가 발생했다면, $php_errormsg 라는 전역변수에 에러 메시지가 담겨 있게 된다. 그러나 @ error-control operator라도 문법 에러의 경우에는 에러 메세지를 disable로 하지 못한다.

주의

현재 @ error-control operator 선행자(prefix)는 스크립트를 중단시킬 정도의 치명적인 에러에 대해서도 에러 레포팅을 하지 않게 한다. 특히 @이 특정 함수의 에러레포팅을 억제 하려고 사용된 경우에, 이 함수가 존재 하지 않거나, 이름을 잘못 쓴 경우 해당 스크립트는 아무런 이유를 표시하지 않고 죽어버리게 된다.

아래에 PHP에서 에러를 다루는 기능에 대한 사용 예를 적어 놓았다. 이 예에서 우리는 파일로(XML 포맷을 사용) 해당 정보의 로그를 남기고, 논리적인 문제로 치명적인 에러가 생긴경우는 개발자에게 e-mail을 보내는 에러 핸들링 함수를 정의하였다.

예 16-1. Using error handling in a script

<?php
// we will do our own error handling
error_reporting(0);

// user defined error handling function
function userErrorHandler ($errno, $errmsg, $filename, $linenum, $vars) {
    // timestamp for the error entry
    $dt = date("Y-m-d H:i:s (T)");

    // define an assoc array of error string
    // in reality the only entries we should
    // consider are 2,8,256,512 and 1024
    $errortype = array (
                1   =>  "Error",
                2   =>  "Warning",
                4   =>  "Parsing Error",
                8   =>  "Notice",
                16  =>  "Core Error",
                32  =>  "Core Warning",
                64  =>  "Compile Error",
                128 =>  "Compile Warning",
                256 =>  "User Error",
                512 =>  "User Warning",
                1024=>  "User Notice"
                );
    // set of errors for which a var trace will be saved
    $user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
    
    $err = "<errorentry>\n";
    $err .= "\t<datetime>".$dt."</datetime>\n";
    $err .= "\t<errornum>".$errno."</errnumber>\n";
    $err .= "\t<errortype>".$errortype[$errno]."</errortype>\n";
    $err .= "\t<errormsg>".$errmsg."</errormsg>\n";
    $err .= "\t<scriptname>".$filename."</scriptname>\n";
    $err .= "\t<scriptlinenum>".$linenum."</scriptlinenum>\n";

    if (in_array($errno, $user_errors))
        $err .= "\t<vartrace>".wddx_serialize_value($vars,"Variables")."</vartrace>\n";
    $err .= "</errorentry>\n\n";
    
    // for testing
    // echo $err;

    // save to the error log, and e-mail me if there is a critical user error
    error_log($err, 3, "/usr/local/php4/error.log");
    if ($errno == E_USER_ERROR)
        mail("phpdev@mydomain.com","Critical User Error",$err);
}


function distance ($vect1, $vect2) {
    if (!is_array($vect1) || !is_array($vect2)) {
        trigger_error("Incorrect parameters, arrays expected", E_USER_ERROR);
        return NULL;
    }

    if (count($vect1) != count($vect2)) {
        trigger_error("Vectors need to be of the same size", E_USER_ERROR);
        return NULL;
    }

    for ($i=0; $i<count($vect1); $i++) {
        $c1 = $vect1[$i]; $c2 = $vect2[$i];
        $d = 0.0;
        if (!is_numeric($c1)) {
            trigger_error("Coordinate $i in vector 1 is not a number, using zero", 
                            E_USER_WARNING);
            $c1 = 0.0;
        }
        if (!is_numeric($c2)) {
            trigger_error("Coordinate $i in vector 2 is not a number, using zero", 
                            E_USER_WARNING);
            $c2 = 0.0;
        }
        $d += $c2*$c2 - $c1*$c1;
    }
    return sqrt($d);
}

$old_error_handler = set_error_handler("userErrorHandler");

// undefined constant, generates a warning
$t = I_AM_NOT_DEFINED;

// define some "vectors"
$a = array(2,3,"foo");
$b = array(5.5, 4.3, -1.6);
$c = array (1,-3);

// generate a user error
$t1 = distance($c,$b)."\n";

// generate another user error
$t2 = distance($b,"i am not an array")."\n";

// generate a warning
$t3 = distance($a,$b)."\n";

?>
이것은 Error Handling and Logging functions에 있는 함수들을 어떻게 사용하는 가를 보여주는 간단한 예이다.

See also error_reporting(), error_log(), set_error_handler(), restore_error_handler(), trigger_error(), user_error()