- Błędów E_NOTICE i E_WARNING NIE przechwycimy klauzulą try/catch,
- Error exception (Traditional error reporting mechanism) !== ErrorException (klasa)
Try/catch/finally: Łapie "od góry do dołu"
<?phpdeclare(strict_types=1);
function foo(int $value) {} ______
| |
try { | |
foo(true); // throws TypeError | |
} catch (TypeError $e) { Najbardziej konkretny
echo 'catch ' . get_class($e); | |
} catch (Error $e) { Ogólniejszy
echo 'catch ' . get_class($e); | |
} catch (Throwable $e) { Najbardziej ogólny
echo 'catch ' . get_class($e); ___| |___
} finally { \ Zawsze /
echo '!'; \ wykona /
} \ /
\ /
// catch TypeError! \ /
\/
______
| |
___| |___
// jeżeli w dalszym ciągu nie \ /
// przechwycimy wyjątku, złapiemy \ /
// go gdy mamy zadeklarowany \ /
// set_exception_handler() \ /
\ /
\/
// jeżeli zabraknie deklaracji set_exception_handler(),
// implementacja set_error_handler() NIE przechwyci błędu.
______
| |
Wyjątek nie przechwycony,
konwertowanie do:
__| |__
\ /
\ /
\ /
\ /
\ /
\ /
\/
FATAL ERROR
Interfejs Throwable został wprowadzona w wersji PHP 7.0 i dziedziczą po niem dwie gałęzie systemu błędów: Exception i Error. Jako, że klasa Exception istniała już od wersji 5.0 zapytasz jak to wtedy wyglądało? Otóż Exception nie rozszerzało żadnej klasy.
Warto wspomnieć o tym, że pola klas Error i Exception:
- message,
- code,
- file,
- line,
Są inicjalizowane w czasie tworzenia obiektu, a nie podczas jego wyrzucania za pomocą słowa kluczowego throw.
Co istotnie, nie jest możliwe bezpośrednie implementowanie po interfejsie Throwable, ale śmiało można Type Hint'ować po nim w klauzulach catch. Cała hierarchia predefiniowanych klas przedstawia się następująco (najistotniejsze klasy z mojego punktu widzenia):
- Throwable - Interfejs
- Error - klasa bazowa dla wewnętrznych błędów PHP
- TypeError,
- ArgumentCountError PHP 7.1,
- ParseError,
- ArithmeticError,
- DivisionByZeroError,
- AssertionError,
- CompileError PHP 7.3,
- Exception
- ErrorException PHP 5.1,
- DOMException PHP 5.0,
- LogicException SPL Exceptions (od PHP 5.1),
- BadFunctionCallException,
- BadMethodCallException,
- LengthException,
- InvalidArgumentException
- DomainException,
- OutOfRangeException,
- RuntimeException SPL Exceptions (od PHP 5.1),
- PDOException
Co ciekawe możesz w catch'ach Type Hint'ować na nieistniejące klasy Error\Exception i z tego powodu nie będzie wyrzucany żaden błąd. Interpreter po prostu nie sparuje wyrzuconego np. wyjątku z nieistniejącą klasą i - jeżeli takowa istnieje - przejdzie do kolejnej klauzuli catch.
Rodziny klas Error/Exception posiadają zaimplementowaną metodę __toString() dzięki czemu możemy stosować echo bezpośrednio na przechwyconych w klauzulach catch obiektach $e.
ErrorException
W wersji PHP 5.1 pojawiła się nowa klasa dziedzicząca po klasie Exception - ErrorException. Jak sugeruje dokumentacja języka - zalecane jest zadeklarowanie nowego error handler'a który przechwytuje błędy typu E_WARNING (2) i E_NOTICE (8) by w przypadku ich wystąpienia wyrzucić wyjątek klasy ErrorException. Dzięki temu obsługa błędów w klasach klienckich nabierze jeszcze bardziej obiektowego charakteru.
ArgumentCountError
TypeError
InvalidArgumentException
BadMethodCallException
DivisionByZeroError
try {
5%0;
} catch (DivisionByZeroError $e) {
echo 'catch'; // wpadnie
}
try {
5/0;
} catch (DivisionByZeroError $e) {
echo 'catch';
}
nie wpadnie w blok catch tylko wyrzuci E_WARNING
Operator Pipeline
try {
foo(); // nieistniejąca funkcja
} catch (TypeError | Error | Exception $e) {
echo 'caught: ' . get_class($e);
}
Kompatybilność wsteczna
Z racji tego że klasy Error, które pojawiły się w wersji 7.0 nie dziedziczą po klasie Exception, dotychczas istniejące bloki try/catch w Twoim kodzie implementowane pod PHP 5.6 - nie zmienią swojego zachowania
Jeżeli migrujesz z wersji 5.6 na 7.0 i zadeklarowałeś klasę o nazwie 'Error' - to musisz ją zmienić ponieważ otrzymasz:
FATAL ERROR Cannot declare class Error, because the name is already in use
Brak komentarzy:
Prześlij komentarz