Wyjątki

Z PHPEdia.pl
Skocz do: nawigacji, wyszukiwania

Czym są wyjątki

Wyjątek wykorzystywany jest do przechwytywania informacji o "nadzwyczajnych" sytuacjach. Pozwala on na redukcję ilości konstrukcji warunkowych i w przypadku zaistnienia wyjątku na przeskoczenie całego bloku kodu. Wyjątki w PHP zostały zaimplementowane począwszy od wersji 5. składnia ich wyrzucania/przechwytywania jest zapożyczona z języków C++ i Java.

Użycie wyjątków

przykładowy kod użycia wyjątków

<?php
class Foo {
    // $bar powinno być liczbą całkowita
    public function __construct($bar) {
        if (!is_int($bar)) {
            throw new InvalidArgumentException('Argument powinien być liczbę całkowitą!'); 
        }
 
        echo 'Konstruktor wywołany z prawidłowym argumentem!';
    }
}
 
try {
    $str = 'aaa';
    $foo = new Foo($str); // wywołujemy konstruktor klasy Foo z argumentem który jest stringiem
 
    echo 'Obiekt klasy Foo został utworzony';
} catch (Exception $e) {
    echo $e;
}?>

Wyjście tego skryptu:

Argument powinien być liczbę całkowitą!
NULL

Instrukcja throw

Instrukcja throw służy do wyrzucania wyjątku. Po słowie throw powinien znaleźć się obiekt klasy Exception lub klasy dziedziczącej po niej. Jeśli kod wywołujący instrukcje throw nie znajduje się w w bloku try, a więc wyjątek przez nią wyrzucony nie może być przechwycony, PHP generuje błąd krytyczny (Fatal Error).

Blok try

W bloku try ograniczonym nawiasami klamrowymi powinien znaleźć się kod, który ewentualnie może wyrzucić jakiś wyjątek. Zauważ, że napotkawszy instrukcję throw, kończy się wykonywanie dalszego kodu zarówno w miejscu gdzie został on wywołany w klasie, jak i w bloku try z którego została wywołana metoda - widać to w pokazanym wyżej przykładzie - skrypt nie wyświetla:

Konstruktor wywołany z prawidłowym argumentem! Obiekt klasy Foo został utworzony

Blok catch

Po bloku try musi nastąpić przynajmniej jeden blok catch. Blok catch pozwala na przechwycenie zaistniałego wyjątku i wykonanie odpowiednich czynności. Instrukcja catch pobiera jeden argument w postaci "NazwaKlasy $zmienna", gdzie NazwaKlasy to rodzaj wyjątku (Exception lub pochodna), a $zmienna to zmienna, za pomocą której będziemy odwoływać się do przechwyconego wyjątku. Możemy napisać kilka następujących po sobie bloków catch - np. dla różnej obsługi różnych typów wyjątków. Zasada jest prosta. Wszystkie wyjątki dziedziczyć bo bazowej klasie Exception. Tzn. że jeśli w instrukcji catch jako typ wyjątku podany Exception (tak jak w przykładzie), złapie on dowolny rodzaj wyjątku. Równie dobrze moglibyśmy próbować złapać tylko konkretny typ wyjątku (np. InvalidArgumentException) lub dowolny wyjątek położony wyżej w hierarchii (np. LogicException, który jest rodzicem InvalidArgumentException i dziedziczy po Exception). przykładowy kod:

<?php
try {
    $bar = new Bar();
    $bar->foo();
} catch (InvalidArgumentException $e) {
    // złapie wszystkie wyjątki typu InvalidArgumentException 
    // oraz wyjątki dziedziczące po tym typie
} catch (LogicException $e) {
    // złapie wszystkie wyjątki typu LogicException oraz wyjątki dziedziczące
    // po tym typie (ale bez Invalid ArgumentException, który jest jego 
    // dzieckiem i został złapany wcześniej)
} catch (Exception $e)
    // złapie dowolny wyjątek, ale bez LogicException i jego dzieci, 
    // ponieważ zostały one złapane w poprzednich blokach catch
}
?>

NOTKA: Wyjątki InvalidArgumentException i LogicException są dostępne od PHP w wersji 5.1!


Należy pamiętać, że blok catch nie służy tylko do wyświetlania błędów. W tym bloku powinniśmy podjąć kroki by ten błąd naprawić, a jeśli jest to niemożliwe zatrzymać działanie skryptu (np. za pomocą instrukcji exit). W kodzie został jedynie wyświetlony błąd, jednak po bloku try-catch nie możemy być pewni czy obiekt $foo istnieje czy nie. Jeśli wystąpił wyjątek zostanie wyrzucony, nie będzie on istniał, tak więc należy się zabezpieczyć przed taką ewentualnością. Dlatego najlepszym wyjściem byłoby wstrzymanie wykonania w bloku catch.

Klasa Exception

właściwości i metody

Klasa Exception posiada szereg właściwości i metod, umożliwiających wyciąganie informacji o wyjątku:

<?php
class Exception
{
protected $message = 'Unknown exception'; // treść wyjątku
protected $code = 0; // kod wyjątku
protected $file; // plik, w którym wystąpił wyjątek
protected $line; // linia, w której wystąpił wyjątek  
 
public function __construct($message = null, $code = 0); // konstruktor
 
final public function getMessage(); // zwraca wiadomość wyjątku
final public function getCode(); // zwraca kod wyjątku
final public function getFile(); // zwraca nazwę pliku
final public function getLine(); // zwraca numer linii
final public function getTrace(); // zwraca tablicę trace 
final public function getTraceAsString(); // zwraca tablicę trace w formie ciągu  
 
/* Do nadpisania */
public function __toString(); // wyjątek w formie ciągu
}        
?>

Wbudowane wyjątki

Od PHP 5.0

W PHP 5.0 wbudowana jest jedynie bazowa klasa dla wyjątków: Exception.

Od PHP 5.1

Od wersji 5.1 zbiór wyjątków zostaje rozszerzony o te ze Standardowej Biblioteki PHP:

Tworzenie własnych klas wyjątków

W PHP można stworzyć własną klasą wyjątku i nadać jej odpowiednią nazwę, aby potem móc np. inaczej obsługiwać każdy rodzaj wyjątku. Tworzenie swojego wyjątku polega po prostu na zdefiniowaniu klasy dziedziczącej po klasie Exception:

<?php
class MyException extends Exception {
 
/**
* Metoda __toString()
* Przekształca wyjątek w ciąg
* Jedyna nadpisywana metoda klasy Exception
*
* @access public
* @return string
*/
public function __toString() {
return '<b>MyException:</b>: ' . $this->getMessage();
}
 
}
?>

przykładowy kod wykorzystujący nową klasą:

<?php
$bar = 'jakasZmienna';
try {
    if(is_int($bar)) {
        throw new Exception('$bar jest liczbę całkowitą');
    } elseif(is_string($bar)) {
        throw new MyException('$bar jest ciągiem');
    }
 
    echo 'blah';
} catch(MyExcpetion $e) {
    echo $e;
} catch(Exception $e) {
    echo 'Wystąpiś wyjątek w pliku ' . $e->getFile() . ' w linii ' . $e->getLine();
}
?>

W zależności od typu zmiennej $bar kod wygeneruje odpowiedni wyjątek, w zależności od wyjątku kod wyświetli odpowiednią wiadomość. Jednak, jako że MyException dziedziczy po Exception, blok catch łapiący ten typ wyjątku musi być nad blokiem łapiącym wyjątek Exception, ponieważ wykonywany jest kod z pierwszego spełniającego kryteria bloku catch jaki zostanie napotkany. Z tego powodu bloki catch łapiące wyjątki typu Exception powinny być zawsze umieszczane jako ostatnie (tak jak np. instrukcja default w konstrukcji switch).

Obsługa nieprzechwyconych wyjątków

Jak wiadomo, dla błędów można ustawić własną obsługę. Podobnie jest z nieprzechwyconymi wyjątkami - służy do tego funkcja set_exception_handler(). Pobiera ona jako argument nazwę funkcji, która ma być uruchomiona, gdy wyjątek nie zostanie w żaden sposób przechwycony. Niestety, wykonywanie skryptu zatrzymuje się po pierwszym 'nieprzechwyceniu' wyjątku.

Polecamy również


Błąd przy generowaniu miniatury File missing
Artykuł Wyjątki został uznany za godny umieszczenia na liście artykułów na medal.

Zapraszamy do głosowania na stronie "Propozycje do artykułów na medal"