SELFPHP

SELFPHP-Druckversion
Original Adresse dieser Seite:
http://www.selfphp.de/praxisbuch/praxisbuchseite.php?site=253&group=44
© 2001-2017 E-Mail SELFPHP OHG, info@selfphp.de
© 2005-2017 E-Mail PHP5 Praxisbuch - Matthias Kannengiesser, m.kannengiesser@selfphp.de


Ausnahmebehandlung


Wenn man sich in der Programmierung mit der Fehlerbehandlung befassen möchte, muss man sich von Anfang an darüber im Klaren sein, dass es dabei nicht um syntaktische Fehler geht. Diese werden bereits vom PHP-Interpreter frühzeitig abgefangen und gemeldet.

Beispiel – fehlerhafter Aufruf von printf()

<?php

printf("Hallo %s" "Matze");

?>

Ausgabe – Syntaxfehlermeldung (parse error)

Parse error: parse error, unexpected T_CONSTANT_ENCAPSED_STRING in...

Bei der Fehlerbehandlung dreht sich alles um die Verarbeitung von Ausnahmen (engl. exceptions). Eine Ausnahme stellt ein Ereignis dar, welches zur Laufzeit eines Programms eintritt und den normalen Kontrollfluss unterbricht. Man kann sagen, Ausnahmen treten immer dann auf, wenn ein Skript vorzeitig aufgrund unerwarteter Umstände abgebrochen wird oder fehlerhafte Ergebnisse liefert.

Hinweis: Solche Ausnahmen werden in der Programmierung auch als Laufzeitfehler oder Ausnahmefehler bezeichnet.

Typische Umstände für eine Ausnahme sind:

Das Ziel bei der Verarbeitung solcher Ausnahmen ist es, möglichst sämtliche Fehler abzufangen und darauf angemessen zu reagieren, und sei es auch nur in Form einer benutzerfreundlichen Fehlermeldung.

In puncto Fehlerbehandlung bot PHP bisher keine vordefinierten Möglichkeiten, um auf Ausnahmen zu reagieren. Als Entwickler war man auf eigene Lösungen angewiesen, beispielsweise durch das Abfangen von Rückgabewerten bei Funktionen. Bei jeder Funktion, egal ob es sich um eine benutzerdefinierte oder vordefinierte Funktion handelte, die einen Fehler verursachen konnte, musste deren Rückgabewert überprüft und an Ort und Stelle entsprechend reagiert werden.

Beispiel – Funktion division()

<?php

function division($a,$b)
{
  return($a/$b);
}


echo division (10,5); // 2
echo division (10,0); // Division by zero

?>

Die erste Wertübergabe führt zu einem sinnvollen Ergebnis, bei der zweiten handelt es sich um die Division durch 0, und solch eine Ausnahme musste in Form einer benutzerdefinierten Lösung abgefangen werden.

Beispiel – Funktion division() mit benutzerdefinierter Ausnahmebehandlung

<?php

function division($a,$b)
{
  // Überprüfung, ob durch Null dividiert werden soll
  if ($b == 0)
  {
    // Gibt benutzerdefinierte Fehlermeldung zurück
    return "Division durch null nicht durchführbar!";
  }
  return($a/$b);
}


echo division (10,5); // 2
echo division (10,0); // Division durch null nicht durchführbar!

?>

Hinweis: Diese Form einer Fehlerbehandlung werden Sie auch zukünftig einsetzen können.
{PSP}In PHP 5 steht Ihnen ein zusätzliches Mittel zur Verarbeitung von Ausnahmen zur Verfügung. Es handelt sich um die try-throw-catch-Fehlerbehandlung, welche auch als Ausnahmebehandlung (engl. exception) bezeichnet wird.

Der Nutzen liegt einerseits in der gewonnenen Flexibilität, da sich beliebige eigene Fehlertypen verwenden lassen, anderseits aber auch in der Möglichkeit, Fehlerbehandlungscodes zu bündeln und somit den Fehler von seiner Behandlung auch örtlich zu trennen, um lesbarere Skripts zu erhalten.

Wenn also etwa eine Methode einen Fehler erkennt, auf den sie nicht reagieren kann, so »wirft« (throw) sie eine Ausnahme des entsprechenden Typs. Der Programmablauf des Programms wird dadurch unterbrochen. Diese Ausnahme wird daraufhin im dafür vorgesehenen catch-Block wieder »aufgefangen« und verarbeitet.

Beispiel – Funktion division() samt try-throw-catch-Fehlerbehandlung

<?php

function division($a,$b)
{
  // Überprüfung, ob durch Null dividiert werden soll
  if ($b == 0)
  {
    // Ausnahme melden (werfen)
    throw new exception("Division durch null nicht durchführbar!");    
  }
  return($a/$b);

}

// Einleiten der Ausnahmebehandlung
try
{
  echo division (10,5); // 2
  echo division (10,0); // Erzeugt eine Ausnahme!  
}
// Verarbeitung des Ausnahmefehlers
catch (exception $fehler)
{
  echo $fehler->getMessage() . "\n";
}
?>

Im vorliegenden Beispiel wird der Ausnahmefehler »Division durch null nicht durchführbar!« ausgegeben. Bei sämtlichen Anweisungen innerhalb des try-Blocks werden eventuelle Ausnahmen abgefangen. Das bedeutet, wenn Sie wie im vorliegenden Fall eine Funktion aufrufen, die eine Ausnahme erzeugt, wird sie abgefangen, solange der Aufruf aus einem try-Block heraus erfolgt. Mithilfe der throw-Anweisung wird der Ausnahmefehler gemeldet. Der Programmablauf wird unterbrochen und der passende catch-Block gesucht. Für die Reaktion auf die Ausnahme ist der catch-Block zuständig. Die Übergabe des Fehlers erfolgt in Form eines Parameters, welcher innerhalb des catch-Blocks abgerufen werden kann. Dieser steht Ihnen somit für die eigentliche Fehlerbehandlung zur Verfügung.

Sollten Sie mit dem Konzept noch nicht aus einer anderen Programmiersprache vertraut sein, können Sie sich die Ausnahmebehandlung von PHP vereinfacht als eine Art Flaschenpost vorstellen.

»Irgendwo auf der Welt tritt ein Ausnahmefall ein. Der in Not Geratene kann sich nicht selbst aus der Lage befreien, kann aber mittels einer in einer Flasche untergebrachten Nachricht versuchen, jemand anderen zu einer geeigneten Reaktion zu bewegen. Er wirft die Flaschenpost ins Meer, irgendjemand wird sie irgendwann und irgendwo aus dem Wasser fischen und hoffentlich angemessen darauf reagieren.«

Diese sicherlich etwas seltsame Metapher zeigt neben dem ungefähren Verhalten auch den eigentlichen Zweck der Ausnahmebehandlung. Sie soll immer dann helfen, wenn etwas Unvorhergesehenes geschieht. Skripts, in denen Ausnahmebehandlungen allgemein und oft zur Kontrolle des Programmablaufs oder zur Kommunikation eingesetzt werden, sind nicht zu empfehlen. Die Flaschenpost ist schließlich auch nur äußerst selten das Kommunikationsmittel der Wahl!

Einige weitere Beispiele sollen Ihnen dabei behilflich sein, die Arbeitsweise von Ausnahmebehandlungen genauer zu betrachten.

Beispiel – Ausnahmebehandlung

<?php

$alter = 20;
$nutzer = "Otto";

try
{
  if ($alter < 18)
  {
    throw new exception($alter . " ist zu Jung!");
  }
  else
  {
    if ($nutzer != "Caroline")
    {
      throw new exception($nutzer . " ist nicht Caroline!");
    }
  }
}
catch (exception $e)
{
  echo $e->getMessage() . "\n";
}
catch (exception $e)
{
  echo $e->getMessage() . "\n";
}

?>
{PSP}Ausgabe
Otto ist nicht Caroline!


Die folgenden Methoden stellt die exception-Standardklasse bereit:

__clone, __construct, getMessage, getCode, getFile, getLine, getTrace, getTraceAsString, und __toString.

Beispiel – Erweiterung von Ausnahmebehandlungen

<?php

class MeineException {
  function __construct($exception) {
     $this->exception = $exception;
  }

  function Display() {
     echo "MeineException: $this->exception<br>";
  }
}

class MeineErweiterteException extends MeineException {
  function __construct($exception) {
     $this->exception = $exception;
  }

  function Display() {
     echo "MeineException: $this->exception<br>";
  }
}

try {
  throw new MeineErweiterteException('Testlauf');
}
catch (MeineException $exception) {
  $exception->Display();
}
catch (Exception $exception) {
  echo $exception;
}

?>

Hinweis: Eine ideale Einsatzmöglichkeit bildet neben jeglichen sensiblen oder fehleranfälligen Codepassagen jede transaktions- oder datenbankbasierte Webanwendung.



Built-In Backtracing

Das Backtracing ist eine äußert nützliche Eigenschaft, die unmittelbar an die Ausnahmebehandlung anknüpft, und sollte im besten Fall während der throw-Anweisung aufgerufen werden mit throw new MeineErweiterteException(debug_backtrace()). Es ermöglicht, die durch die exception-Standardklasse ausgelösten Ausnahmebedingungen bzw. Fehler zu präzisieren, eine Liste der Funktionsaufrufe an der aktuellen Position (Zeilennummer) zurückzugeben und ein Backtrace aufzuzeichnen. Somit werden Webanwendungen leichter zu debuggen und zu warten sein, und Fehler sind besser zu reproduzieren. Dabei liefert die debug_backtrace()-Funktion ein Array mit vier Rückgabewerten zurück: