에러
여기서 에러라는 것은 문법 에러와 치명적 에러 등을 말합니다. 에러는 보통 문법 에러, 컴파일 에러 등 컴파일 타임에 나타나는 것이 일반적이며 예외는 데이터베이스 연결 예외 등 런타임에 나타나는 것이 일반적입니다. PHP 언어에서는 에러를 처리할 수 있는 몇 가지 기법이 있는데, 알아보도록 하겠습니다.
error_reporting(int)
에러 발생 레벨을 조정할 수 있습니다. 상수 E_
로 시작하는 것이 일반적입니다. 예를 들면 다음과 같이 레벨을 조정할 수 있습니다. 예제에 나온 설정이 일반적으로 사용되고, 프로덕션에서는 꺼놓는 경우도 있습니다. 사실 보안을 위해서라면 꺼놓는게 좋기는 합니다.
int $level |
에러 보고 레벨 |
error_reporting(E_ALL & ~E_NOTICE);
error_log(string [, int [, string]])
에러를 콘솔, 파일 등으로 보고할 수 있습니다. 함수 자체가 오래된 함수이기 때문에 굳이 사용할 필요는 없을지도 모르겠지만, 에러를 보고한다고 할 때 이 함수를 사용하는 것은 코드를 읽는 사람의 입장에서 유용할 것입니다. 두번째 파라매터는 어디로 에러를 보낼 것인가에 대한 것인데, 0(system logger), 3(file) 번을 많이 사용할 것입니다.
int $message |
에러 메시지 |
int $message_type |
에러 타입 |
string $destination |
에러를 보낼 주소 또는 파일의 경로 |
error_log('Hello, world', 3, __DIR__ . '/logs/log.log');
set_error_handler(callable [, int])
에러를 핸들링하기 위한 기본적인 함수로, 이것을 사용하면 발생하는 에러에 대해 통제할 수 있습니다. error_reporting()
을 사용하기 보다는 해당 함수에서 에러를 제어하는 것이 조금 더 나은 것으로 보입니다. 파라매터로는 기본적으로 콜백함수를 받고, 그 다음에 타입을 받습니다. 해당 함수에 빈 콜백을 던지면 에러가 발생은 하되 무시됩니다.
callable $error_handler |
에러를 처리할 콜백함수 |
int $error_types |
처리할 에러 타입 |
이 함수는 fatal error 에 대해서는 처리할 수 없습니다. try ~ catch
에서 별도로 처리해야 합니다.
error_handler(int, string [, string [, int ]])
에러 핸들러 함수는 몇 가지 파라매터를 받습니다. 여기서 발생한 에러에 대해서 제어를 할 수 있습니다. 빈 함수를 넘겨주면 에러를 무시하는 듯한 효과를 줄 수도 있습니다.
int $errno |
에러의 타입 |
string $errstr |
에러 메시지 |
string $errfile |
에러가 발생한 파일 |
int $errline |
에러가 발생한 라인 |
set_error_handler(function ($errno, $errstr) {
switch ($errno) {
case E_USER_ERROR:
var_dump($errstr);
break;
default:
throw new ErrorException($errstr, 0, $errno);
}
});
restore_error_handler()
설정한 에러 핸들러를 초기화할 수 있습니다. 이전에 설정된 에러 핸들러로 다시 되돌아갑니다.
restore_error_handler();
trigger_error(string [, int])
해당 함수를 사용하면 사용자 에러를 보낼 수 있습니다. PHP 내부에서 발생하는 에러가 아니라 임의로 발생시킨 에러입니다. E_USER_
로 시작하는 상수입니다.
string $error_msg |
에러 메시지 |
int $error_type |
사용자 에러 타입 |
trigger_error('Hello, world', E_USER_ERROR);
@ 연산자
@
를 사용하면 발생한 에러에 대해 무시할 수도 있습니다. 이에 대해서는 PHP: 연산자에서 언급한 바 있습니다. 여기서 언급할만한 사항은 속도가 느리니 자주 사용하지는 말라는 것입니다.
보안
error_reporting(0)
error_reporting()
에 0 을 설정하면 어떠한 에러도 보고하지 않습니다. 에러를 사용자에게 나타낸다는 것은 어플리케이션의 정보를 일부 노출시키는 것이므로 주의해야 합니다. 따라서 프로덕션 환경에서는 해당 함수에 0 을 설정함으로써 에러를 보고하지 않도록 하는 것도 방법입니다. 물론, 이렇게 설정은 하지 않고 에러 핸들러로 잡아서 처리를해도 좋습니다.
ini_set('display_errors', 'Off')
해당 설정이 활성화되어 있으면 놀랍게도 웹상에 에러 텍스트가 표시되므로 개발 도중에는 사용해도 괜찮겠지만, 프로덕션에서는 사용하면 안 됩니다. 따라서 display_errors
는 비활성화 하는 것이 좋습니다.
모든 에러를 표시하기
모든 에러를 표시하려면 위의 것과 반대로 설정하면 됩니다. 아래와 같이 말이죠. 이 설정은 프로덕션에서 사용하면 절대 안 됩니다. 이는 어플리케이션에서 발생하는 일반적인 오류를 잡아주기 때문에, 데이터베이스 처리 등에서 발생하는 에러에 대해서는 나타내지 못할 수도 있습니다.
error_reporting(E_ALL);
ini_set('display_errors', 'On');
예외
예외에 대한 처리는 에러에 대한 것보다도 오히려 간단합니다. 의도치 않게 에러 파트에서 레퍼런스 처럼 함수를 나열해 버렸는데, 예외에서는 딱히 그럴만한 것이 없습니다.
try ~ catch ~ finally
많은 언어에서 그렇듯, 해당 문법은 예외를 처리할 때 사용합니다. try
블럭에서 예외가 발생하면 catch
에서 해당 예외를 잡고 처리할 수 있습니다. 이러한 catch
블럭은 한 개가 아닌, 여러 개가 올 수도 있습니다. finally
블럭은 예외 발생 여부와 상관없이 항상 실행합니다. 예를 들어 데이터베이스 커넥션이 있으나, 쿼리에서 에러가 난 경우 커넥션 자원 해제코드를 finally
블럭에 넣을 수 있겠죠. 에러가 나든 안 나든 자원은 해제되어야 합니다.
try {
throw new Exception('Hello, world');
} catch (Exception $e) {
var_dump($e->getMessage());
} finally {
var_dump('finally');
}
set_exception_handler(callable)
에러 핸들러와 마찬가지로 예외도 별도로 핸들러를 지정해줄 수 있습니다.
callable $exception_handler |
예외를 처리할 핸들러 |
exception_handler(Exception)
Exception $e |
처리할 예외 |
set_exception_handler(fn (Exception $e) => var_dump($e->getMessage()));
restore_exception_handler()
등록된 예외 핸들러를 해제할 수 있습니다.
restore_exception_handler()
Exception
기본적으로 사용하는 예외 클래스는 Exception
클래스입니다. 이를 상속하게 되면 사용자 정의 예외를 만들어낼 수 있습니다. 서드파티 라이브러리를 사용하게 될 때 기본적으로 정의되지 않은 여러 예외가 존재할 수 있는 이유는 이것이 가능하기 때문입니다. 빌트인에 존재하는 예외로는 ErrorException
등이 있습니다.
class MyException extends Exception
{
public function __construct($message = "", $code = 0, $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
Error
try ~ catch
구문을 Exception
이외에 Error
클래스로도 잡을 수 있습니다. 사실 try ~ catch
구문은 Throwable
인터페이스를 구현한 클래스라면 잡을 수 있습니다. 즉, Exception, Error
클래스입니다. Error
클래스는 놀랍게도 set_error_handler()
가 처리하지 못하는 fatal error
를 잡을 수 있습니다.
try {
new MyClass();
} catch (Error $e) {
// -> Class 'MyClass' not found
var_dump($e->getMessage());
}
Throwable
이것은 try ~ catch
로 처리할 수 있도록, 정확히는 던질 수 있도록(Throwable) 해주는 인터페이스입니다. 다만, 사용자 정의 예외를 만들 때 해당 인터페이스를 구현하여 나타내지는 말라고 이야기하고 있습니다.
PHP classes cannot implement the Throwable interface directly, and must instead extend Exception.
더 읽을거리
https://www.inflearn.com/course/php7-reboot