예외

목차

PHP에는 다른 프로그래밍 언어와 유사한 예외 모델이 있습니다. 예외를 throw해서, PHP 안에서 잡을(catch) 수 있습니다. 잠재적인 예외를 쉽게 포착하기 위해 코드를 try 블록으로 묶을 수 있습니다. 잠재적인 예외를 잡기 위해서 코드를 try 블록으로 감쌀 수 있습니다. 각 try는 최소한 하나의 catchfinally 블록을 가져야 합니다.

예외가 발생하고 현재 함수 범위에 catch 블록이 없으면 예외는 일치하는 catch 블록을 찾을 때까지 호출 함수에 대한 호출 스택을 "버블업"합니다. 도중에 만나는 모든 finally 블록이 실행됩니다. 호출 스택이 일치하는 catch 블록을 만나지 않고 전역 범위로 풀린 경우 전역 예외 처리기가 설정되지 않은 한 프로그램은 치명적인 오류와 함께 종료됩니다.

throw된 개체는 Exception 클래스의 인스턴스이거나 Exception의 하위 클래스여야 합니다. 그렇지 않은 객체를 던지려고 하면 PHP 치명적인 오류가 발생합니다.

PHP 8.0.0부터 throw 키워드는 표현식이며 모든 표현식 컨텍스트에서 사용할 수 있습니다. 이전 버전에서는 명령문이었고 자체 라인에 있어야 했습니다.

catch

catch 블록은 throw된 예외에 응답하는 방법을 정의합니다. catch 블록은 처리할 수 있는 하나 이상의 예외 또는 오류 유형을 정의하고 선택적으로 예외를 할당할 변수를 정의합니다. (PHP 8.0.0 이전에는 변수가 필요했습니다.) throw된 개체의 유형과 일치하는 throw된 예외 또는 오류가 발생한 첫 번째 catch 블록은 개체를 처리합니다.

여러 catch 블록을 사용하여 다른 클래스의 예외를 catch할 수 있습니다. 정상적인 실행(try 블록 내에서 예외가 throw되지 않은 경우)은 순서대로 정의된 마지막 catch 블록 이후에 계속됩니다. catch 블록 내에서 예외를 throw(또는 re-throw)할 수 있습니다. 그렇지 않으면 트리거된 catch 블록 이후에 실행이 계속됩니다.

예외가 발생하면 명령문 다음의 코드는 실행되지 않으며 PHP는 일치하는 첫 번째 catch 블록을 찾으려고 시도합니다. 예외가 catch되지 않으면 set_exception_handler()로 핸들러가 정의되지 않은 한 "Uncaught Exception ..." 메시지와 함께 PHP 치명적인 오류가 발생합니다.

PHP 7.1.0부터 catch 블록은 파이프(|) 문자를 사용하여 여러 예외를 지정할 수 있습니다. 이것은 다른 클래스 계층의 다른 예외가 동일하게 처리되는 경우에 유용합니다.

PHP 8.0.0부터 catch된 예외에 대한 변수 이름은 선택 사항입니다. 지정하지 않으면 catch 블록이 계속 실행되지만 throw된 개체에 액세스할 수 없습니다.

finally

finally 블록은 catch 블록 뒤나 대신 지정할 수도 있습니다. finally 블록 내의 코드는 예외가 발생했는지 여부와 관계없이 trycatch 블록 이후와 정상 실행이 재개되기 전에 항상 실행됩니다.

한 가지 주목할만한 상호 작용은 finally 블록과 return 문 사이입니다. try 또는 catch 블록 내에서 return 문이 발생하면 finally 블록이 계속 실행됩니다. 또한 return 문은 만났을 때 평가되지만 finally 블록이 실행된 후에 결과가 반환됩니다. 또한 finally 블록에 return 문이 포함되어 있으면 finally 블록의 값이 반환됩니다.

Global exception handler

예외가 전역 범위까지 버블링되도록 허용된 경우 설정된 경우 전역 예외 처리기에 의해 catch될 수 있습니다. set_exception_handler() 함수는 다른 블록이 호출되지 않으면 catch 블록 대신 호출될 함수를 설정할 수 있습니다. 효과는 본질적으로 전체 프로그램이 해당 함수를 catch로 사용하여 try-catchcatch 블록에 래핑된 것과 같습니다.

주의

메모:

내부 PHP 함수는 주로 오류 보고를 사용하며 최신 객체 지향 확장만 예외를 사용합니다. 그러나 오류는 ErrorException을 사용하여 예외로 쉽게 변환될 수 있습니다. 그러나 이 기술은 치명적이지 않은 오류에서만 작동합니다.

예제 #3 오류 보고를 예외로 변환

                  
<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
    throw new ErrorException($message, 0, $severity, $filename, $lineno);
}

set_error_handler('exceptions_error_handler');
?>
                  
                

표준 PHP 라이브러리(SPL)는 많은 내장 예외를 제공합니다.

Examples

예제 #4 예외 던지기

                  
<?php
function inverse($x) {
  if (!$x) {
    throw new Exception('Division by zero.');
  }
  return 1/$x;
}

try {
  echo inverse(5) . "\n";
  echo inverse(0) . "\n";
} catch (Exception $e) {
  echo 'Caught exception: ',  $e->getMessage(), "\n";
}

// Continue execution
echo "Hello World\n";
?>
                  
                

위의 예는 다음을 출력합니다.

                  
0.2
Caught exception: Division by zero.
Hello World
                  
                

예제 #5 finally 블록을 사용한 예외 처리

                  
<?php
function inverse($x) {
  if (!$x) {
      throw new Exception('Division by zero.');
  }
  return 1/$x;
}

try {
  echo inverse(5) . "\n";
} catch (Exception $e) {
  echo 'Caught exception: ',  $e->getMessage(), "\n";
} finally {
  echo "First finally.\n";
}

try {
  echo inverse(0) . "\n";
} catch (Exception $e) {
  echo 'Caught exception: ',  $e->getMessage(), "\n";
} finally {
  echo "Second finally.\n";
}

// Continue execution
  echo "Hello World\n";
?>
                  
                

위의 예는 다음을 출력합니다.

                  
0.2
First finally.
Caught exception: Division by zero.
Second finally.
Hello World
                  
                

예제 #6 finally 블록과 return 간의 상호 작용

                  
<?php

function test() {
    try {
        throw new Exception('foo');
    } catch (Exception $e) {
        return 'catch';
    } finally {
        return 'finally';
    }
}

echo test();
?>
                  
                

위의 예는 다음을 출력합니다.

                  
finally
                  
                

예제 #7 중첩 예외

                  
<?php

class MyException extends Exception { }

class Test {
  public function testing() {
      try {
        try {
            throw new MyException('foo!');
        } catch (MyException $e) {
          // rethrow it
          throw $e;
        }
      } catch (Exception $e) {
        var_dump($e->getMessage());
      }
  }
}

$foo = new Test;
$foo->testing();

?>
                  
                

위의 예는 다음을 출력합니다.

                  
string(4) "foo!"
                  
                

예제 #8 다중 catch 예외 처리

                  
<?php

class MyException extends Exception { }

class MyOtherException extends Exception { }

class Test {
  public function testing() {
    try {
      throw new MyException();
    } catch (MyException | MyOtherException $e) {
      var_dump(get_class($e));
    }
  }
}

$foo = new Test;
$foo->testing();

?>
                  
                

위의 예는 다음을 출력합니다.

                  
string(11) "MyException"
                  
                

예제 #9 잡힌 변수 생략

PHP 8.0.0 이상에서만 허용됩니다.

                  
<?php

class SpecificException extends Exception {}

function test() {
  throw new SpecificException('Oopsie');
}

try {
  test();
} catch (SpecificException) {
  print "A SpecificException was thrown, but we don't care about the details.";
}
?>
                  
                

예제 #10 잡힌 변수 생략

PHP 8.0.0 이상에서만 허용됩니다.

                  
<?php

class SpecificException extends Exception {}

function test() {
  do_something_risky() or throw new Exception('It did not work');
}

try {
  test();
} catch (Exception $e) {
  print $e->getMessage();
}
?>