CompZone.Org :: Artykuły :: PHP
Która technologia najbardziej Cię interesuje?
PHP
ASP
AJAX
SQL
JavaScript
Inna
Sonda Wyniki

Add to Google

Obsługa i tłumienie błędów w PHP

Pisząc skrypt powinniśmy eliminować wszystkie błędy i ostrzeżenia. Jednak z błędami wywołanymi przez zachowanie użytkowników czy nieprawidłową konfigurację. Te błędy trzeba albo wyświetlić, albo zachować do pliku. Ważna jest także możliwość debugowania w przypadku nieoczekiwanego błędu. W tym artykule pokaże prosty przykład takiego mechanizmu.

Wyciszanie błędu

W konfiguracji PHP możemy ustawić czy PHP ma wyświetlać błędy, a jeżeli tak, to jakie ważne. Błędy w PHP zostały podzielone na kilka grup (np. ostrzeżenia, błędy, uwagi). Standardowo PHP wyświetla wszystkie błędy i ostrzeżenia z wyjątkiem uwag. Na serwerach komercyjnych często spotykamy się z tym, że żadne błędy nie są wyświetlane. Jednak czasem ustawienia mogą okazać się inne niż przypuszczaliśmy. Może okazać się, że ustawiono raportowanie wszystkich błędów. Wtedy nasz skrypt może siać nieprzyjemnymi uwagami. Najszybciej nie mając dostępu do konfiguracji można to zmienić używając funkcji error_reporting. Przyjmuje ona jako parametr poziom wyświetlanych błędów.

Oto kilka najważniejszych:

  • E_ERROR - błąd wykonania
  • E_WARNING – ostrzeżenia
  • E_NOTICE – uwaga
  • E_USER_ERROR – błąd wywołany przez skrypt (przez trigger_error)
  • E_USER_WARNING – ostrzeżenie wywołane przez skrypt (przez trigger_error)
  • E_USER_NOTICE – uwaga wywołana przez skrypt (przez trigger_error)
  • E_ALL – raportowanie wszystkich błędów
  • E_STRICT – uwagi czasu wykonania zapewniające m. in. przyszłą kompatybilność (od PHP5)

Warto dodać, że E_ALL nie uruchamia E_STRICT. Parametry można łączyć używając operatorów bitowych. Na przykład wyłączenia raportowania uwag (E_NOTICE) może wyglądać następująco:

error_reporting(E_ALL & !E_NOTICE); //wszystkie błędy bez uwag

Możemy też włączyć wyświetlanie błędów (E_ERROR) z ostrzeżeniami (E_WARNING) i w php5 z E_STRICT:

error_reporting(E_ERROR | E_WARNING | E_STRICT);

Żeby wyłączyć raportowanie wszystkich błędów wystarczy podać parametr 0:

error_reporting(0);

Własna obsługa błędów w PHP

W trakcie pisania możliwość szybkiego znalezienia błędu jest cudowna. Dobra obsługa błędów można nam w tym znacznie pomóc. Choć są do tego wyspecjalizowane skrypty, które w trakcie rozwijania kodu pozwalają szybko je szukać (jak xdebug), to możemy akurat nie mieć nic pod ręką. Poza tym taki system jest wręcz nie do przecenienia, gdy w fazie używania programu pojawi się krytyczny błąd. Dzięki dobrze napisanej własnej obsłudze błędów możemy liczyć na znalezienie błędu.

 <?php
//define('DEBUG', 1);
set_error_handler('errorhandler');
function unroll_args($array){
$args = array();
foreach($array as $arg){
if(is_array($arg)){
$args[] = 'Array('.unroll_args($arg).')';
}else if(is_string($arg)){
$args[] = 'String('.strlen($arg).') '.$arg.'"';
}else{
$args[] = (string)$arg;
}
}
return join(', ',$args);
}
function errorhandler($errno, $errstr, $errfile, $errline, $errcontext){
$date = date('d-m-y H:i:s');
$dmfile = date('dmyhis');
if(!defined('E_STRICT'))define('E_STRICT', -1);
$errortype = array (
E_ERROR => "Error",
E_WARNING => "Warning",
E_PARSE => "Parsing Error",
E_NOTICE => "Notice",
E_CORE_ERROR => "Core Error",
E_CORE_WARNING => "Core Warning",
E_COMPILE_ERROR => "Compile Error",
E_COMPILE_WARNING => "Compile Warning",
E_USER_ERROR => "User Error",
E_USER_WARNING => "User Warning",
E_USER_NOTICE => "User Notice",
E_STRICT => "Runtime Notice"
);
$bt = debug_backtrace();
$btstr = '';
foreach($bt as $line=>$funct){
$btstr .= "t".'Call: '.$funct['function'] .' in file: '.$funct['file']
.
' on line '.$funct['line'];
if(is_array($funct['args'])){
$btstr .= ' with args ('.unroll_args($funct['args']).')';
}
$btstr.="n";
}
switch($errno){
case E_USER_ERROR:
case E_ERROR:
case E_WARNING:
$fplog = fopen('log/crash-'.$dmfile.'.log','w');
fwrite($fplog, 'BŁÂĄD('. $errortype[$errno].') w linii '. $errline.' w pliku '. $errfile."nt$errstrn");
fwrite($fplog, "Backtrace: n".$btstr);
fclose($fplog);
default:
if(defined('DEBUG')){
echo '<p>BŁÂĄD('.$errortype[$errno]. ') w linii '. $errline.' w pliku '.$errfile.'<br/><b>'.$errstr.'</b></p>';
}
}
}
?>

Wyjaśnię teraz z mniejszą bądź większą dokładnością jak to działa. Przede wszystkim funkcja set_error_handler podmienia funkcję obsługującą błędy na moją własną (errorhandler). Funkcja ta przyjmuje 4 parametry. Pierwszy – typ błędu, drugi – opis błędu, trzeci – plik błędu, czwarty – linia błędu. Piąty parametry jest opcjonalny. Jest to kontekst wykonania i przechowuje wszystkie zadeklarowane w tym zakresie wywołania błędu. Dalej następuje pobranie daty w 2 różnych formatach. W przypadku użycia jednego pliku logowania warto jej użyć. Linia:

 <?php
//...
if(!defined('E_STRICT'))define('E_STRICT', -1);
//...
?>

zapewnia kompatybilność ze wcześniejszymi wersjami PHP. Dalej funkcja debug_backtrace zwraca tablicę wywołanych funkcji, która w następnych liniach jest przetwarzana do ciągu znaków. Funkcja unroll_args, służy do rozwinięcia tablicy parametrów przekazywanych funkcji do postaci ciągu znaków. Jeżeli przekazany parametr jest tablicą to funkcja wywołuje się rekurencyjnie. Później w zależności o rodzaju błędu tworzony jest raport w osobnym katalogu. Każdy raport ma osobny plik. Raport w nazwie ma datę utworzenia i przechowuje takie dane jak typ błędu, miejsce wystąpienia oraz dane wywołanych funkcji. Gdy ustawimy stałą DEBUG (trzeba odkomentować pierwszą linie z define), wszystkie błędy, uwagi i ostrzeżenia będą też wyświetlały się w przeglądarce.

Poniższy przykład demonstruje wykorzystanie tego skryptu i wynik jego działania:

test.0.php

 <?php
include('error.php');
include('test.1.php');
?>

test.1.php

 <?php
require_once('error.php');
makenoise();
function makenoise(){
for($i=0;$i<10;$i++){
doRandom($i);
}
}
function doRandom($i){
echo "$i - ";
echo ((float)$i/(9-$i))."<br>n";
}
?>

Przykładowy raport

 Ł

Do poprawnego działania tego skryptu musisz utworzyć katalog log/ i nadać mu uprawnienia 777. W tym skrypcie można dużo ulepszyć, w szczególności zróżnicować sposób wyświetlania błędów, ostrzeżeń i uwag. Tylko błędy krytyczne zapisywać do osobnych plików. W ostrzeżenia, uwagi i informacje o błędach (odwołanie do raportu) tylko w jednym pliku log. Warto byłoby dopracować wyświetlanie błędów na stronie oraz dodać możliwość podglądu kontekstu błędów (5 parametr uchwytu błędów).

Wywoływanie błędów

W celach testowych tego skryptu i oczywiście w przypadkach kiedy potrzebujecie wywołać błąd wystarczy posłużyć się funkcją trigger_error. Przyjmuje on jako parametry opis błędu oraz typ błędu.

 <?php
//...
trigger_error('Nie poprawny typ pliku', E_USER_WARNING);
//...
?>

Przywrócenie pierwotnej obsługi błędów

W celu przywrócenia standardowej obsługi błędów należy posłużyć się funkcją restore_error_handler. Ustawia ona poprzedni uchwyt błędów, więc jeżeli użyto funkcji set_error_handler tylko raz, ustawi ona standardowy, wbudowany w PHP model obsługi błędów. Funkcja ta zwraca zawsze wartość true.

Podsumowanie

Umiejętne stworzenie systemu logowania i obsługi błędów może usprawnić znacząco proces szukania błędów, jak również umożliwić znalezienie błędu, gdy pojawi się on w trakcie użytkowania skryptu. Wszystkie stałe błędów można znaleźć w naszym manualu.

Kodie @ 11-07-2006 16:02
Brak komentarzy...
Copyright © 2005-2006 Compzone.Org. Kopiowanie i wykorzystywanie materiałów zawartych na tej stronie bez zgody autora zabronione!