PHpullh
심층 가이드/PHP/에러 처리

PHP · 심층 가이드

PHP 에러 처리 완전 정리

Throwable 계층과 전역 핸들러, 경고의 예외 승격, 재시도와 JSON 오류 응답까지 PHP 애플리케이션이 실패했을 때 무엇을 남기고 무엇을 돌려줄지 설계합니다.

주제 14개 · 예제 코드 포함 · 최종 수정 2026-08-30 · 작성 pullh 편집팀

PHP에는 실패를 알리는 경로가 하나가 아닙니다. 예외를 던지는 함수가 있고, false를 반환하며 경고만 찍는 오래된 표준 함수가 있고, 타입 위반처럼 Error로 올라오는 엔진 레벨 실패가 있습니다. PHP 7에서 Throwable 인터페이스가 도입되면서 ExceptionError를 한 자리에서 잡을 수 있게 됐지만, 경고와 통지는 여전히 예외가 아니라서 try 블록으로는 걸리지 않습니다. 이 세 갈래를 하나의 흐름으로 모으는 것이 에러 처리 설계의 실질입니다.

try catch 기본finally 로 정리 작업으로 골격을 잡은 뒤, 커스텀 예외 클래스다중 catch로 실패를 종류별로 구분하는 습관을 들이면 됩니다. 그다음이 핵심인데, 에러를 예외로 승격에서 set_error_handler로 경고를 ErrorException으로 바꾸고 전역 예외 핸들러로 마지막 안전망을 두면 모든 실패가 한 통로로 모입니다. 여기까지 오면 도메인 예외 매핑JSON 에러 응답 포맷으로 내부 예외를 사용자에게 보여 줄 형태로 번역하는 작업이 자연스럽게 이어집니다.

안전망에는 구멍이 있습니다. set_exception_handler는 메모리 한도나 실행 시간 초과 같은 치명적 오류를 잡지 못하고, 이때는 register_shutdown_function 안에서 error_get_last()를 확인하는 수밖에 없습니다. 또 finally 블록에서 return하거나 새 예외를 던지면 원래 예외가 조용히 사라집니다. 정리 코드는 값을 돌려주지 않게 유지하십시오. PDO 예외 모드를 켜지 않으면 질의 실패가 예외 없이 false로만 돌아와 다음 줄에서 엉뚱한 오류로 터집니다.

01try catch 기본

예외를 발생시키고 잡는 PHP의 가장 기본적인 흐름을 보여주는 예제입니다.

PHP code

<?php
try {
    throw new RuntimeException('boom');
} catch (RuntimeException $e) {
    echo $e->getMessage();
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

02finally 로 정리 작업

성공 여부와 무관하게 자원을 정리하는 finally 블록 예제입니다.

PHP code

<?php
$resource = fopen('php://temp', 'r+');

try {
    fwrite($resource, 'php');
} finally {
    fclose($resource);
    echo "closed";
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

03커스텀 예외 클래스

도메인 의미를 담은 예외 클래스를 직접 정의하는 예제입니다.

PHP code

<?php
class DomainException extends RuntimeException {}

throw new DomainException('invalid state');
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

04다중 catch

비슷한 처리 흐름을 여러 예외 타입에 묶는 다중 catch 예제입니다.

PHP code

<?php
try {
    throw new InvalidArgumentException('bad input');
} catch (InvalidArgumentException | RuntimeException $e) {
    echo $e::class;
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

05Throwable 전체 처리

Exception뿐 아니라 Error까지 모두 잡고 싶을 때 Throwable을 쓰는 예제입니다.

PHP code

<?php
try {
    strlen([]);
} catch (Throwable $e) {
    echo $e::class;
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

06전역 예외 핸들러

애플리케이션 끝단에서 예외를 한 번 더 모아 처리하는 전역 핸들러 예제입니다.

PHP code

<?php
set_exception_handler(function (Throwable $e): void {
    echo '[handled] ' . $e->getMessage();
});

throw new RuntimeException('global');
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

07에러를 예외로 승격

전통적인 PHP warning/error를 예외 흐름으로 통합하는 예제입니다.

PHP code

<?php
set_error_handler(function (int $severity, string $message, string $file, int $line): void {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

try {
    strpos();
} catch (Throwable $e) {
    echo $e::class;
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

모든 에러를 예외로 바꾸면 라이브러리 호환성에 영향을 줄 수 있으니 범위를 신중히 정해야 합니다.

08ValueError 다루기

내장 함수가 잘못된 인자로 던지는 ValueError를 처리하는 예제입니다.

PHP code

<?php
try {
    array_rand([], 1);
} catch (ValueError $e) {
    echo $e->getMessage();
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

09assert 사용

개발 단계에서 불변 조건을 빠르게 검증하는 assert 예제입니다.

PHP code

<?php
assert_options(ASSERT_EXCEPTION, 1);

try {
    assert(1 === 2, 'unexpected');
} catch (AssertionError $e) {
    echo $e->getMessage();
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

10PDO 예외 모드

PDO를 예외 모드로 두고 데이터베이스 오류를 일관되게 처리하는 예제입니다.

PHP code

<?php
$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $pdo->query('SELECT * FROM missing_table');
} catch (PDOException $e) {
    echo 'db error';
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

11도메인 예외 매핑

기술 예외를 도메인 맥락이 담긴 상위 예외로 감싸는 예제입니다.

PHP code

<?php
function createEmail(string $value): string {
    if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException('invalid email');
    }
    return $value;
}

try {
    createEmail('oops');
} catch (InvalidArgumentException $e) {
    throw new RuntimeException('user input error', previous: $e);
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

12재시도 래퍼

실패 가능성이 있는 작업을 제한 횟수만큼 재시도하는 래퍼 예제입니다.

PHP code

<?php
function retry(int $times, callable $task): mixed {
    beginning:
    try {
        return $task();
    } catch (Throwable $e) {
        if (--$times > 0) {
            goto beginning;
        }
        throw $e;
    }
}

echo retry(2, fn () => 'ok');
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

13스택 트레이스 로깅

메시지와 스택 트레이스를 분리해서 남기는 기본 로깅 예제입니다.

PHP code

<?php
try {
    throw new RuntimeException('boom');
} catch (Throwable $e) {
    error_log($e->getMessage());
    error_log($e->getTraceAsString());
}
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

14JSON 에러 응답 포맷

API 서버에서 실패 응답을 일관된 JSON 포맷으로 만드는 예제입니다.

PHP code

<?php
function errorResponse(string $message, int $status = 400): string {
    http_response_code($status);
    return json_encode(['ok' => false, 'message' => $message], JSON_UNESCAPED_UNICODE);
}

echo errorResponse('invalid payload');
알아두면 좋은 점

예외 처리 예제는 로그, 사용자 메시지, 복구 전략을 분리해서 읽으면 실전에 바로 연결됩니다.

자주 하는 실수

예외를 잡고 아무 일도 하지 않으면 문제를 숨기기만 하고 복구는 되지 않습니다.

정리하며

  • set_error_handler로 경고를 ErrorException으로 승격해 실패 경로를 하나로 모읍니다.
  • 치명적 오류는 register_shutdown_function과 error_get_last로만 기록할 수 있습니다.
  • finally에서 return하거나 예외를 던지면 원래 예외가 사라지니 정리만 수행합니다.
  • PDO는 연결 직후 ERRMODE_EXCEPTION을 지정해 질의 실패를 즉시 드러냅니다.

더 깊이 들어가고 싶다면 PHP 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.