Welcher Programmierer kennt das nicht, man benötigt zu Testzwecken den Inhalt einer bestimmten Variable. Im Unterscheid zu den meisten Hochsprachen besitzen viele Editoren und Entwicklungsumgebungen aber keine Debugging-Funktionen. Was liegt da näher die Variable einfach via echo oder print() auszugeben:
Code:
echo $variable
Nun besteht aber oft das Problem, dass vor dieser Ausgabe schon Text ausgegeben wurde und dass man nicht nur eine Variable benötigt. Bei mir kamen dann oft wilde Konstrukte heraus, um den Ausgabe Text irgendwie hervorzuheben:
Code:
echo "<br/><br/><b>*****$variable1*****$variable2</b><br/><br/>";
Spätestens hier fängt das ganze dann an, umständlich zu werden. Also: Eine Vereinfachung muss her. Am besten in Form einer Funktion, die das alles automatisch macht. So ist meine erste Testfunktion entstanden:
Code:
function test()
{
$arg_list = func_get_args();
echo "<br/>================================================<br/>";
for ($i = 0; $i < func_num_args(); $i++)
{
if (is_array($arg_list[$i]) )
{
echo $var_names[$i] . ':<br/><b style="color:#BB0000;">';
echo nl2br( print_r($arg_list[$i],true) );
echo "</b><br/>";
}
else
{
echo "Wert $i" . ': <b style="color:#000000;">' . $arg_list[$i] . "</b>" .
( is_int($arg_list[$i]) ? " <i>" . date("D, d.m.Y H:i:s",$arg_list[$i]) . "</i>" : "") . "<br/>\n";
}
}
echo "================================================<br/>";
}
Nicht schön, nicht elegant, aber es funktioniert! Über die PHP-Funktion func_get_args() kann man der Testfunktion beliebig viele Parameter übergeben, dessen Werte dann zeilenweise ausgegeben werden. Arrays werden automatisch über print_r entsprechend auseinandergedröselt und farbig markiert. Falls es sich bei den Werten um Integer handelt wird dieser Zusätzlich noch als Timestamp interpretiert.
Wirklich schön wäre es gewesen, wenn man die Namen der übergebenen Variablen noch hätte ausgeben können, doch leider gibt es in PHP keine Funktion mit dieses möglich ist. Die Lösung hier für ist so einfach wie effektiv:
Code:
function t()
{
.
.
.
$info = debug_backtrace();
$php_file = file($info[0]['file']);
$function_call = strstr($php_file[$info[0]['line']-1],$info[0]['function'] . '(');
$var_names = substr($function_call, strpos($function_call, '(')+1, strpos($function_call, ');') - strpos($function_call,'(')-1 );
$var_names = explode(',', $var_names);
.
.
.
Das sieht auf den ersten Blick erstmal kompliziert aus, ist aber nicht wirklich schwer: Über die PHP-Funktion, debug_backtrace() lassen sich Informationen zur Ablaufverfolgung auslesen, insbesondere die Datei und Zeilennummer des in der die gerade laufende Funktion aufgerufen wurde. In der Folgenden Zeile wird schlicht und ergreifend die Datei in der die Funktion aufgerufen wurde in die Variable $php_file eingelesen. In $function_call wird die Zeile des Funktionsaufrufes gespeichert und in den folgenden Zeilen die einzelnen Parameter in den Klammern des Aufrufes extrahiert und im array $var_names gespeichert. Die Funktion schaut also quasi selber in der Datei nach wie und mit welchen Parametern sie aufgerufen wurde. Das ist zwar alles andere als performant, allerdings spielt Performance beim Erstellen einer Webseite in aller Regel eine sehr untergeordnete Rolle.
Die Variablen werden dann später in der Schleife entsprechend benannt.
Hier nun die fertige Funktion:
Code:
function t()
{
global $test_function_microtime;
$arg_list = func_get_args(); //übergebene Parameter holen
$num_args = func_num_args(); //Daten zur Ablaufverfolgung generieren
$info = debug_backtrace(); //Datei öffnen, welche die Funktion aufgerufen hat
//an die Funktion Übergebene Variablennamen extraieren
if($num_args)
{
$php_file = file($info[0]['file']);
$function_call = strstr($php_file[$info[0]['line']-1],$info[0]['function'] . '(');
$var_names = substr($function_call, strpos($function_call, '(')+1, strpos($function_call, ');') - strpos($function_call,'(')-1 );
$var_names = explode(',', $var_names);
}
echo "<br/>================================================<br/>";
for ($i = 0; $i < $num_args; $i++)
{
//Arrays
if (is_array($arg_list[$i]) )
{
echo $var_names[$i] . ':<br/><b style="color:#BB0000;">';
echo nl2br( print_r($arg_list[$i],true) );
echo "</b><br/>";
}
//falls die Variable $sql heißt, das ganze als Textarea ausgeben
elseif($var_names[$i] == '$sql')
{
echo $var_names[$i] . ':</br><b style="color:#000000;">';
echo '<form><textarea name="test" cols="100" rows="10" onclick="this.form.test.select();">';
echo $arg_list[$i];
echo '</textarea></form>';
}
else
{
echo $var_names[$i] . ': <b style="color:#000000;">' . $arg_list[$i] . "</b>";
echo ( is_int($arg_list[$i]) ? " <i>" . date("D, d.m.Y H:i:s",$arg_list[$i]) . "</i>" : "") . "<br/>\n";
}
}
echo "<br/>Timestamp: <b>" . time() . "</b><br/>";
echo "Aufruf in: <b>" . $info[0]['file'] . "</b><br/>";
echo "Zeile: <b>" . ($info[0]['line']) . "</b><br/>";
//Zeitdifferenz seit dem letzten Aufruf generieren
if ($test_function_microtime)
{
$time_diff = microtime(true) - $test_function_microtime;
echo "Zeit seit dem letzten Aufruf: <b>" . $time_diff . " Sekunden </b><br/>";
}
$test_function_microtime = microtime(true);
echo "================================================<br/>";
return microtime(true);
}
Wie man sieht wurde das ganze noch etwas aufgebohrt. Da Programmierer grundsätzlich eher zur faulen Spezies gehören, wurde der Name der Funktion von test() nochmals auf t() gekürzt. Desweiteren wurde neben arrays noch ein weiterer Sonderwert eingeführt. SQL-Statements (welche die Funktion anhand des Namens der Variable '$sql' erkennt) werden gesondert in einer Textarea ausgegeben, so dass man sie leicht in die Zwischenablage kopieren und etwa in phpMyAdmin testen kann.
Bei aufwändigen PHP-Skripten kann es leicht passieren, dass man die Performance von aufwändigen Rechenoperationen oder komplexen Datenbankaufrufen, testen oder vergleichen muss. Dazu hat die Funktion auch noch eine virtuelle Stopuhr eingebaut. Über die global definierte Variable $test_function_microtime (der umständliche Name resultiert aus dem Bemühen Überschneidungen im Namensraum mit eventuellen Scripten zu vermeiden), wird die Zeit in Mikrosekunden seit dem letzten Aufruf der Funktion ausgerchnet. Diese Zeit wird auch für eventuelle weitere Berechnungen zurückgegeben. So kann man sehr einfach die Zeit aufwändiger PHP-Operationen protokollieren indem man die Test-Funktion einfach direkt vor und hinter der zeitkritischen Operation ausführt.
Zu guter Letzt wird noch ein aktueller Timestamp sowie die Dateipfad und Zeile des Aufrufes ausgegeben um die Übersicht zu behalten.
Mit dieser Funktion hat man in weniger als 60 Zeilen Code ein einfaches und mächtiges Werkzeug in der Hand mit dem sich schnell, einfach und komfortabel Werte aus PHP-Variablen ausgeben lassen.