W PHP5 wyjątku są obiektami, co pozwala nam na dopasowywanie ich do swoich potrzeb. Głównym obiektem jest klasa Exception(). Przyjrzyjmy się dokładniej jej budowie, aby wiedzieć z czym dokładnie mamy do czynienia.
<?php class Exception { protected $message = 'Unknown exception'; // exception message protected $code = 0; // user defined exception code protected $file; // source filename of exception protected $line; // source line of exception function __construct(string $message=NULL, int code=0); final function getMessage(); // message of exception final function getCode(); // code of exception final function getFile(); // source filename final function getTrace(); // an array of the backtrace() final function getTraceAsString(); // formated string of trace /* Overrideable */ function _toString(); // formated string for display } ?>
Opisze mniej więcej o co chodzi w danych właściwościach i metodach:
Właściwości
● Exception :: message – Informacja o tym, co spowodowało wystąpienie wyjątku,
● Exception :: code – Definiowany przez programistę kod wyjątku,
● Exception :: file – Pliku w którym wystąpił wyjątek,
● Exception :: line – Linia w której wystąpił wyjątek.
Metody
● Exception :: __constructor( $sMessage, $iCode )
- Informacja co spowodowało wyjątek
- Numer wyjątku
● Exception :: getMessage()
- Zwraca informacje co spowodowało wyjątek
● Exception :: getCode()
- Zwraca kod wyjątku
● Exception :: getFile()
- Zwraca ścieżkę do pliku, gdzie wystąpił wyjątek
● Exception :: getTrace()
- Zwraca ślad w postaci tablicy (z funkcji backtrace() )
● Exception :: getTraceAsString()
- Zwraca ślad z postaci łańcucha znaków
● Exception :: __toString()
- Magiczna metoda… Jeżeli będziemy chcieli potraktować obiekt jako string, ta funkcja ma zwrócić string jakiego oczekujemy (najczęściej zwraca się tutaj Exception :: message )
Tak wygląda budowa głównej klasy wyjątków. Warto zapoznać się z jej budową, ponieważ to na jej postawie będziemy tworzyć własne wyjątki, które będą nas informować o problemach w naszych programach.
Zatem jak działają wyjątki? W ciele try{} dajemy kod w którym spodziewamy się wystąpienia wyjątku, nie należy zawierać za dużych fragmentów kodu. Zawieramy tylko tyle kodu, ile jest niezbędne do działania jakiegoś fragmentu aplikacji. Zależy nam na tym, że jeżeli zostanie zwrócony wyjątek, to dzięki catch(){} będziemy w stanie obsłużyć wyjątek tak, aby dalsza część aplikacji działała już poprawnie.
Tak jak już wspomniałem po bloku try{} umieszczamy blok/i catch(){} w którym wypisujemy jakiego wyjątku oczekujemy, a następnie w ciele bloku piszemy kod odpowiedzialny za “zreperowanie”. Bloków catch(){} umieszczamy tyle, ile wyjątków możemy się spodziewać i podołamy ich obsłudze.
Zademonstruje przykładowy szkic:
Try { // Blok w którym spodziewamy sie wyjątku } catch (exception $ePierwszy ) { // obsługa pieszego spodziewanego wyjątku } catch (exception $eNty ) { // obsługa kolejnego wyjątku }
Na początku uruchomiony jest blok try{}, jeżeli podczas jego działania zostanie zwrócony jakikolwiek wyjątek to następuje uruchomcie kolejnych bloków catch(){}, tj. Jeżeli wyjątek nie pasuje do pierwszego bloku sprawdzany jest kolejny (całość przypomina w pewnym sensie działanie switch()’a). Wyjątki dopasowywane są do bloków catch(){} po typie obiektu(nazwach klasy Exception). W wypadku braku wystąpienia wyjątku w bloku try{}, bloki catch(){} w ogóle nie zostają uruchomione.
Już mniej więcej wiemy jak obsłużyć wyjątki, teraz nauczymy się jak je zwracać. Do zwrócenia wyjątku używamy throw. Działa ona podobnie do return, z tą różnica że nie zwraca danych tylko wyrzuca wyjątek który łapiemy blokiem try{} i obsługujemy w pasującym ciele catch(){}.
Przykład:
<?php $sPath = './router.php'; try { if( !file_exists( $sPath ) ) { throw new Exception( 'plik nie istnieje!' ); } include $sPath; if( !class_exists( 'Router' ) ) { throw new Exception( 'Klasa Router nie istnieje!' ); } $Router = new Router(); } catch( Exception $Ex ) { echo '<p>Wystąpiły problemy!</p>'."\n"; echo '<p>',$Ex,'</p>'; } ?>
W bloku try{} został umieszczony kod odpowiedzialny za sprawdzenie czy istnieje plik i klasa niezbędna do poprawnego działania naszego skryptu. W przypadku kiedy plik lub klasa nie istnieją zostaje zgłoszony wyjątek – skrypt po wyrzuceniu wyjątku nie wykonuje się dalej, tzn po uruchomionej konstrukcji throw od razu następuje przeskok do bloku catch(){}.
Ponieważ posiadamy jedna instrukcje catch(){} a typ klasy wyjątku [throw new Exception()] zgadza się właśnie z zdeklarowanym w tym bloku [catch( Exception $Ex )] zostaje uruchomione ciało właśnie tego bloku catch(){}.
W bloku catch(){} powinny zostać wykonane operacje odpowiedzialne za “odratowanie kodu” my jednak wyświetlimy tylko że pojawiły się problemy, obsłużeniem ich zajmiemy się trochę potem.
Kod pokazuje proste zastosowanie wyjątków, ale nic specjalnego on sobą nie reprezentuje. Żeby można było zacząć korzystać z pełnych dobrodziejstw wyjątków musimy przyjrzeć sie dokładniej ich budowie.
PHP5 udostępnia nam bardzo wygodny sposób obsługi zdarzeń powodujących różnego rodzaju komplikacje. Pomysł został zaczerpnięty z innych języków, także jego działanie jest niemal identyczne z tym, jakie spotykany w Javie. Oczywiście mowa tutaj o Exception (z ang. Wyjątki). Dzięki nim możemy oznajmić aplikacji, że wystąpił błąd z którym dalej ona nie możne poprawnie funkcjonować. W przeciwieństwie do funkcji die() czy też exit(), które kończą wykonywanie programu, wyjątki umożliwiają nam podjęcie odpowiednich kroków mających na celu eliminację problemu. Oczywiście moglibyśmy stosować wszędzie funkcje/metody, które zwracają true lub false, w zależności od tego czy jej działanie zakończyło się sukcesem. Pomysł często stosowany, lecz przy większych systemach można bardzo szybko stracić rachubę, co powoduje błąd (gdyż mamy tylko wiedzę, o tym że działanie funkcji/metody się nie powiodło, nie znamy przyczyn). Kod staje się także dużo bardziej nie czytelny, ogromne ilości instrukcji warunkowych w znacznym stopniu wpływając negatywnie na czytelność kodu. Można także próbować korzystać z funkcji trigger_error(), która to “wytwarza” błąd. Stosuje się ją powszechnie w bibliotekach pisanych dla PHP4. Moim zdaniem jednak, to narzędzie jest bardzo nie wygodne, w dodatku nie oferuje nam możliwości obsłużenia błędu tylko nas o nim informuje.