[함수] set_error_handler 함수 한계 극복하기
PHPSchool을 안지는 오래되었지만 글은 정말 오랜만에 적는 것 같네요.
최근에는 php로 프로젝트를 진행하고 있습니다. 예전에 했던 php와 많이 달라졌네요. ㅎㅎ
많은 분들이 알고 계신 것이겠지만 혹여나 도움되길 바라며.... ^^
블로그에 올린 글이라 반말입니다. 양해주시길... ^^
set_error_handler()나 set_exception_handler()로 php상에서 발생하는 에러나 예외를 모두 원하는 방식으로 처리하려고 했다. 가령, 중간에 에러를 출력하지 않고 DB나 Text로 저장하던가 특정 에러는 e-mail로 보내줘야 한다던가 하는 일들을 위해서이다. 또는 앱과 같은 외부플랫폼과 통신하기 위해 특정 통신 프로토콜(json이나 xml등)을 사용하게 되는데 예외 및 에러가 발생할때 이 규격에 맞지 않게 외부에 그냥 텍스트를 출력해버리면 곤란하기 때문이다. 그래서 이 함수를 사용한 코드의 인터페이스는 아래처럼 만들수 있게 된다.
=============================================
class Core {
static public function run() {
header('Content-Type:application/json;charset=utf-8');
error_reporting( E_ALL | E_STRICT );
ini_set( 'display_errors', 0 ); //에러를 출력하지 않는다.
set_exception_handler( array( __CLASS__, '__exception_handler' ) );
set_error_handler( array( __CLASS__, '__error_handler' ) );
.....
}
static public function __exception_handler( $e ) { .... }
static public function __error_handler( $no, $str, $file, $line ) { .... }
}
Core::run(); //구동시작
=============================================
내 코드는 json을 반환하고 싶은 것이고 모든 에러를 리포팅하되 출력하지는 못하도록 했다. 원래 목적대로 모든 에러나 예외를 global 수준에서 처리하도록 하기 위해서이다.
하지만 set_error_handler()는 한가지 예외가 있었다. php 레퍼런스에 보면 다음문구가 있다.
=============================================
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
=============================================
즉, set_error_handler() 함수는 "E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING" 에러는 처리 못함을 알려주고 있다. 실제 코딩상에 발생되는 오류나 문제를 set_error_handler()로 커버할 수 없다는 뜻이다. 맞는 말이긴 하지만 나의 목표에는 부족함이 있다.
검색해보니 이런 형태로 커버하는 것도 보았다.
=============================================
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
ini_set('error_prepend_string','<head><META http-equiv=" refresh"="" content="0;URL=/error.php?url='.$url.'&msg=');
ini_set('error_append_string','">');
=============================================
물론 일부 해결방법이긴 하지만 그저 텍스트를 출력하는 템플릿만 바꿨을 뿐이다. 뭔가 오류발생시 따로 가공해야한다면 부족함은 여전하다.
조금더 검색해보니 register_shutdown_function() 함수와 error_get_last() 함수를 사용하는 방법이 있다.
아래코드는 아래 링크에 답글에 있는 일부이다.
http://stackoverflow.com/questions/2331582/catch-php-fatal-error
=============================================
define('E_FATAL', E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
E_COMPILE_ERROR | E_RECOVERABLE_ERROR);
define('ENV', 'dev');
//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);
register_shutdown_function('shut');
set_error_handler('handler');
//Function to catch no user error handler function errors...
function shut(){
$error = error_get_last();
if($error && ($error['type'] & E_FATAL)){
handler($error['type'], $error['message'], $error['file'], $error['line']);
}
}
function handler( $errno, $errstr, $errfile, $errline ) {
switch ($errno){
case E_ERROR: // 1 //
$typestr = 'E_ERROR'; break;
case E_WARNING: // 2 //
$typestr = 'E_WARNING'; break;
case E_PARSE: // 4 //
$typestr = 'E_PARSE'; break;
case E_NOTICE: // 8 //
$typestr = 'E_NOTICE'; break;
case E_CORE_ERROR: // 16 //
$typestr = 'E_CORE_ERROR'; break;
case E_CORE_WARNING: // 32 //
$typestr = 'E_CORE_WARNING'; break;
case E_COMPILE_ERROR: // 64 //
$typestr = 'E_COMPILE_ERROR'; break;
case E_CORE_WARNING: // 128 //
$typestr = 'E_COMPILE_WARNING'; break;
case E_USER_ERROR: // 256 //
$typestr = 'E_USER_ERROR'; break;
case E_USER_WARNING: // 512 //
$typestr = 'E_USER_WARNING'; break;
case E_USER_NOTICE: // 1024 //
$typestr = 'E_USER_NOTICE'; break;
case E_STRICT: // 2048 //
$typestr = 'E_STRICT'; break;
case E_RECOVERABLE_ERROR: // 4096 //
$typestr = 'E_RECOVERABLE_ERROR'; break;
case E_DEPRECATED: // 8192 //
$typestr = 'E_DEPRECATED'; break;
case E_USER_DEPRECATED: // 16384 //
$typestr = 'E_USER_DEPRECATED'; break;
}
$message = ''.$typestr.': '.$errstr.' in '.$errfile.' on line '.$errline.'
';
if(($errno & E_FATAL) && ENV === 'production'){
header('Location: 500.html');
header('Status: 500 Internal Server Error');
}
if(!($errno & ERROR_REPORTING))
return;
if(DISPLAY_ERRORS)
printf('%s', $message);
//Logging error on php file error log...
if(LOG_ERRORS)
error_log(strip_tags($message), 0);
}
ob_start();
@include 'content.php';
ob_end_flush();
=============================================
그렇다. register_shutdown_function() 함수는 뭔가 php가 모든 일을 마치고 종료되었을때나 exit()로 종료되었을때 인자로 등록한 핸들러 함수가 호출되게 한다. 즉 뭔가 마무리 하고 싶을때나 처리하고 싶은 일이 있을때 사용할 수 있다. 나의 경우에는 에러가 발생하는 경우 처리하고 싶은 것이므로 처음 코드를 다음처럼 만들면 된다.
=============================================
class Core {
static public function run() {
header('Content-Type:application/json;charset=utf-8');
error_reporting( E_ALL | E_STRICT );
ini_set( 'display_errors', 0 ); //에러를 출력하지 않는다.
set_exception_handler( array( __CLASS__, '__exception_handler' ) );
set_error_handler( array( __CLASS__, '__error_handler' ) );
register_shutdown_function( array( __CLASS__, '__shutdown_handler' ) );
.....
}
static public function __exception_handler( $e ) { .... }
static public function __error_handler( $no, $str, $file, $line ) { .... }
static public function __shutdown_handler() {
$e = error_get_last();
if( $e ) {
self::__error_handler( $e['type'], $e['message'], $e['file'], $e['line'] );
}
}
}
Core::run(); //구동시작
=============================================
이제 왠만한 에러, 예외는 내가 통제할 수 있게 되었다.
원본 : http://blog.jidolstar.com/849
error_handler 를 등록했으므로 echo 로 뿌리지 않는 한 display_error 정의와 상관 없이 에러가 출력되지 않을겁니다.
.data.json, .data.xml 같은 확장자에 rewrite 를 걸어서 요청에 따른 자동 구별이 되게 하면 편리할 것 같네요.
/query/name.php 인데
/query/name.data.json 로 요청이오면 name.php 를 실행하지만 결과는 json
/query/name.data.xml " " " " 결과는 xml
출처 phpschool
'개발-PHP' 카테고리의 다른 글
[함수] 제로보드 댓글 스팸 동시 전체삭제 (0) | 2016.03.30 |
---|---|
[함수] [함수 셀렉트박스] 만들기 처음으로 올림 ㅋ (0) | 2016.03.30 |
[함수] [수정]php 순환참조(RECURSION) 에 안전한 JSON, Array, Object 다루는 Tool 모음 (0) | 2016.03.30 |
[함수] 다들 아실것 같지만...올려봐요,,자릿수만큼 문자열 채우기... (0) | 2016.03.30 |
[함수] redis_cache (그누보드 함수캐쉬. redis 버젼) (0) | 2016.03.30 |