PHP/Fehlersuche

Aus Mikiwiki
< PHP
Wechseln zu: Navigation, Suche

Hilfe bei der Fehlersuche

Der einfachste Weg zur Fehlersuche ist das systematische Auskommentieren von Befehlen, die als mögliche Fehlerursache in Frage kommen.

Die Funktion "var_dump" kann genutzt werden, um zu erkennen, wie PHP Variablen zuordnet. Als Argument wird der Name einer Variablen angegeben.

<?php
$test = "abc";
var_dump($test);
echo "<br />\n";
$test = array(123, 456, "xyz");
echo "<pre>";
var_dump($test);
echo "</pre>";
?>

string(3) "abc"

array(3) {
  [0]=>
  int(123)
  [1]=>
  int(456)
  [2]=>
  string(3) "xyz"
}

Etwas umfangreicher und vor allem bei Arrays auch unleserlicher sind die Ausgaben von "print_r". Bei der Ausgabe globaler Variablen mit einer Referenz auf sich selbst (wie "$GLOBALS") schreibt "print_r" eine entsprechende Nachricht in die betreffende Zeile.

Beide Funktionen eignen sich auch, um den tatsächlichen Datentyp einer Variablen zu ermitteln.

Fehlerbehandlungsroutinen

Allgemein kann man sich eine Eigenschaft von PHP zunutze machen, die in der Abarbeitung logischer Ausdrücke begründet liegt. Angenommen es werden problematische Funktionen aufgerufen.

$var = @f_kritisch($parameter);

In diesem Fall könnte ebensogut folgende Zeile geschrieben werden, ohne dass sich die Funktionsweise ändert. Für PHP ist das ein normaler logischer Ausdruck. Aus Performancegründen werden solche Ausdrücke nur so lange bearbeitet, bis das Ergebnis feststeht. Bei einer "or"-Verknüpfung (logisches oder) ist das Ergebnis "TRUE", wenn einer der beiden Ausdrücke "TRUE" ist. Wird also die kritische Funktion "f_kritisch" richtig abgearbeitet und gibt "TRUE" zurück, so wird PHP den Ausdruck nicht weiter untersuchen und im Skript weiterfahren. Gibt die Funktion aber "FALSE" zurück, muss PHP auch den zweiten Teil untersuchen. das bei der Funktion "f_kritisch" vorangestellte "@"-Zeichen unterdrückt die hausinternen Fehlermeldungen und Warnungen.

$var = @f_kritisch($parameter) or error_check($message, $flag);

Als Fehlerbehandlung bietet sich eine Funktion "error_check" an, wie im folgenden Beispiel gezeigt. Die Anzeige mit einem JavaScript-Fenster verhindert dabei, dass das Layout der Seite durch die Meldungen zerstört wird. Dabei ist der Umgang mit "$php_errormsg" nicht ganz so trivial. Die Ausgabe des folgenden Skripts ist nur im Quelltext sichtbar.

<?php
function error_check($message, $flag) 
{
  printf("<script language=JavaScript>\n");
  printf("alert('%s');",$message);
  printf("</script>");
  if ($flag) return false;
  return true;
}

function f_kritisch()
{      
  $fh = fopen("xx", "r");
  $GLOBALS['php_errormsg'] = $php_errormsg;   
  return $fh;
}

ini_set("track_errors", "1");
$var = @f_kritisch() or error_check($php_errormsg, FALSE);
echo $var;
?>

<script language=JavaScript> alert('fopen(xx) [<a href='function.fopen'>function.fopen</a>]: failed to open stream: No such file or directory');</script>

Die Fehlervariable "$php_errormsg"

Die letzte Fehlermeldung wird in der Variablen "$php_errormsg" gespeichert. Werden Fehler unterdrückt, so können hier trotzdem die Meldungen ausgelesen werden. Voraussetzung ist, dass in der Konfigurationsdatei "php.ini" folgender Eintrag steht. Der Standardwert ist 0, also erfolgt keine Speicherung. Nach der Installation werden die Fehlermeldungen deshalb nicht gespeichert.

track_errors = 0;

Mittels "ini_set" kann der Wert zur Laufzeit geändert werden.

ini_set("track_errors", "1");

Etwas kritischer ist die Tatsache, dass die Fehlermeldung immer in die aktuelle Symboltabelle geschrieben wird. Das ist entweder der globale Adressraum, wenn der Fehler im Hauptprogramm ausgelöst wird, oder innerhalb einer Funktion. Im obigen Beispielskript wird der Fehler innerhalb der Funktion "f_kritisch" behandelt. Um über die Meldung auch ausserhalb der Funktion verfügen zu können, wird diese ausdrücklich in die globale Symboltabelle übertragen.

$GLOBALS['php_errormsg'] = $php_errormsg;

Konsequenter, aber auch deutlich aufwendiger, wäre die Übertragung des gesamten Fehlerkonzepts auf "try/catch"-Strukturen.

Debug-Funktionen

PHP stellt einige Funktionen für das Debugging zur Verfügung. Dies ersetzt keinesfalls den Komfort echter Debugger-Software, hilft jedoch bei den ersten Schritten. Debuggen heisst vor allem, sich vollkommen über den inneren Zustand des Programms im Klaren zu sein. Der Zustand einzelner Variablen kann mit den bereits erwähnten "is_*"-Funktionen getestet werden. Listen definierter Werte ermitteln folgende Funktionen.

Funktion Beschreibung
get_defined_vars Gibt ein Array mit allen Variablen zurück, einschliesslich der in den Variablen enthaltenen Werte.
get_defined_functions Ermittelt die definierten Funktionen. Gibt ein Array mit den Schlüsseln "internal" und "user" zurück, die wiederum Arrays mit den Namen interner bzw. benutzerdefinierter Funktionen enthalten.
get_defined_constants Listet alle Konstanten auf.

Das folgende Beispiel zeigt die Verwendung der Funktion "get_defined_vars". Da die Werte der Variablen hier nicht interessieren, wird mit "array_keys" ein Array der Schlüssel erstellt und mit "print_r" ausgegeben.

<pre>
<?php
$definedvariables = array_keys(get_defined_vars());
print_r($definedvariables);    
?>
</pre>;
Array
(
    [0] => GLOBALS
    [1] => _ENV
    [2] => HTTP_ENV_VARS
    [3] => _POST
    [4] => HTTP_POST_VARS
    [5] => _GET
    ...
)

Bei Funktionen funktioniert das ähnlich. Das folgende Beispiel zeigt, wie die Anzahl der internen Funktionen und die Liste der benutzerdefinierten ausgegeben wird.

<pre>
<?php
function InternalNamesNumber($array)
{
  $countfunction = "count";
  echo "Anzahl interner Funktionen: {$countfunction($array['internal'])}<br />\n";
}

function ShowUserNames($array)
{
  for ($i = 0; $i < count($array['user']); $i++)
  {
    printf("%04d: %s<br />\n", $i, $array['user'][$i]);
  }
}

$definedvariables = get_defined_functions();
InternalNamesNumber($definedvariables);
ShowUserNames($definedvariables);
?>
</pre>

Anzahl interner Funktionen: 1304
0000: internalnamesnumber
0001: showusernames