너의 개발은/PHP

PHP: 에러와 예외 (try, catch, finally)

에러

여기서 에러라는 것은 문법 에러치명적 에러 등을 말합니다. 에러는 보통 문법 에러, 컴파일 에러 등 컴파일 타임에 나타나는 것이 일반적이며 예외는 데이터베이스 연결 예외 등 런타임에 나타나는 것이 일반적입니다. 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.

 

 

PHP 7+ 프로그래밍: 리부트 - 인프런

기초 문법부터 내장 함수, 웹 보안, 게시판 만들기까지 PHP 언어를 시작하는 분들을 위해 바이블이 될 수 있게 만들어보고자 하는 마음으로 이번 강좌를 만들어보았습니다. 입문 웹 개발 프로그��

www.inflearn.com

 

PHP 7+ 프로그래밍: 객체지향 - 인프런

PHP 객체지향, 내장 클래스, PSR, Composer, MVC(Model, View, Controller)까지 모던 PHP를 익히기 위한 근간을 이야기합니다. 초급 프로그래밍 언어 알고리즘 PHP 객체지향 알고리즘 온라인 강의 모던 PHP 프로��

www.inflearn.com