Najlepszy sposób na obsługę błędów na stronie php?

Teraz moje strony wyglądają mniej więcej tak:

if($_GET['something'] == 'somevalue')
{
    $output .= 'somecode';

    // make a DB query, fetch a row
    //...
    $row = $stmt->Fetch(PDO::ASSOC);

    if($row != null)
    {
        $output .= 'morecode';

        if(somethingIsOK())
        {
            $output .= 'yet more page output';
        }
        else
        {
            $error = 'something is most definitely not OK.';
        }
    }
    else
    {
        $error = 'the row does not exist.';
    }
}
else
{
    $error = 'something is not a valid value';
}

if($error == '') // no error
{
    //display $output on page
}
else // an error
{
    // display whatever error occurred on the page
}

Sposób, w jaki robię rzeczy działa, ale jest to bardzo uciążliwe i żmudne dla tego, co jest prawdopodobnie oczywiste: Załóżmy, że wywołuję funkcję gdzieś w środku mojego kodu, lub chcesz sprawdzić wartość zmiennej, lub zweryfikować zapytanie DB zwróciło poprawny wynik, a jeśli się nie powiedzie, chcę wypisać błąd? Musiałbym zrobić kolejny blok if / else i przenieść cały kod wewnątrz nowego bloku if. To nie wygląda na jak inteligentny sposób robienia rzeczy.

Czytałem o try / catch i myślałem o umieszczeniu całego mojego kodu w instrukcji try, a następnie pozwól kodowi działać sekwencyjnie bez żadnych bloków if / else, a jeśli coś się nie powiedzie, po prostu wyrzuć wyjątek. Z tego, co przeczytałem, to zatrzymałoby wykonanie i sprawiłoby, że przeskoczyłoby prosto do bloku catch (tak jak polecenie failed if przejdzie do bloku else), gdzie mógłbym następnie wypisać komunikat o błędzie. Ale czy jest to dopuszczalne lub standardowa praktyka?

Jaki jest najlepszy sposób radzenia sobie z błędami, śmiertelnymi lub nie, w aplikacji php, która buduje i wyświetla stronę HTML? Nie chcę po prostu umrzeć z pustym ekranem, ponieważ byłoby to bardzo przyjazne dla użytkownika, ale zamiast tego chcę wypisać wiadomość w treści strony, nadal pozwalając na wyświetlenie nagłówka i stopki.

Dzięki za radę!

Author: Nate, 2012-08-10

8 answers

Jest wiele sposobów, na które możesz sobie z tym poradzić i szczerze mówiąc żaden z nich nie jest z natury 'właściwy'.

Będziesz musiał sam zdecydować, która metoda jest dla ciebie bardziej "wygodna" - zawsze jest to kwestia preferencji (chociaż są pewne techniki, których powinieneś unikać i nie bez powodu).

Będzie to bardzo zależało od tego, jak podzielisz swoją logikę, jednak zwykle załączam cały kod, który może zwracać nie-fatalne błędy wewnątrz funkcji i używam zwracanej wartości wspomniana funkcja wskazuje, że wystąpił błąd.

Dla błędów krytycznych używam WYJĄTKÓW (z try-catch blokami).

Teraz dla jasności:

  • błąd nie-krytyczny jest błędem, z którego można odzyskać - co oznacza, że nawet jeśli coś poszło nie tak, nadal istnieje jakiś kod, który można wykonać i wygenerować cenne dane wyjściowe. Na przykład, jeśli chcesz uzyskać bieżący czas za pomocą protokołu NTP, ale serwer nie odpowiedział, możesz zdecyduj się na użycie funkcji local time i nadal Wyświetlaj użytkownikowi cenne dane.
  • błąd krytyczny to błąd, z którego nie będziesz w stanie odzyskać - co oznacza, że stało się coś naprawdę złego i jedyne, co możesz zrobić, to powiedzieć użytkownikowi, że strona nie może zrobić tego, o co została poproszona. Na przykład, jeśli pobierałeś dane ze swojej bazy danych i otrzymałeś SQL Exception - nie ma wartościowych danych do pokazania i możesz tylko poinformować użytkownika o to.

Błędy inne niż fatalne (użycie funkcji return)

Dobrym przykładem użycia funkcji-returns jako sposobu radzenia sobie z nie-fatalnymi problemami byłaby funkcja, która próbuje wyświetlić zawartość jakiegoś pliku na stronie , gdy nie jest to głównym celem strony (na przykład masz funkcję, która wyświetla Znaczki, pobrane z pliku tekstowego, na każdej stronie - wiem, że jest to naciągane, ale proszę mi wybaczyć).

function getBadge($file){
    $f = fopen($file,'r');
    if(!$f){
        return null;
    }
    .. do some processing ..
    return $badges;
}

$badges = getBadges('badges.txt');
if(!$badges){
    echo "Cannot display badges.";
} else {
    echo $badges;
}
.. carry on doing whatever page should be doing ..

W fakt, sama funkcja fopen jest tego przykładem- zwróci .

Zwraca wskaźnik zasobu pliku po pomyślnym zakończeniu lub FALSE po błędzie.


Fatal-Errors (using exceptions - try-catch)

Jeśli masz jakiś fragment kodu, który musi zostać wykonany, ponieważ jest dokładnie tym, czego chciał użytkownik (na przykład czytając wszystkie wiadomości z bazy danych i wyświetlając je użytkownikowi), możesz użyć WYJĄTKÓW. Weźmy prosty przykład - użytkownik odwiedził swój profil i chciał zobaczyć wszystkie wiadomości, które dostał (Załóżmy, na razie, że są one przechowywane w zwykłym tekście). Możesz mieć funkcję:

function getMessages($user){
    $messages = array();
    $f = fopen("messages_$user.txt","r");
    if(!$f){
        throw new Exception("Could not read messages!");
    }
    ... do some processing ...
    return $messages;
}

I użyj go tak:

try{
    ..do some stuff..
    $messages = getMessages($_SESSION['user'])); //assuming you store username in $_SESSION
    foreach($messages as $msg){
        echo $msg."<br/>";
    }
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}

Teraz to mogłoby się przydać, gdybyś miał skrypt 'najwyższego poziomu', który wykonałby cały inny kod. Oznacza to, że na przykład w twoim index.php miałbyś po prostu:

try{
    .. execute some code, perform some functions ..
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}
Nie nadużywaj WYJĄTKÓW!

Cokolwiek robisz, nigdy nie używaj WYJĄTKÓW jako sposób, aby sprawdzić coś, co można odzyskać. Przeczytaj na innym pytaniu (pełne uznanie należy do Anton Gogolev {26]} za bardzo dobre wyjaśnienie tego, jak również innych odpowiedzi) , dlaczego tak jest.

Czytaj dalej

Teraz nie ma lepszego sposobu, aby nauczyć się radzić sobie z błędami niż spróbować kilku rzeczy i zobaczyć, co jest dla ciebie dobre. Poniżej można znaleźć przydatne:

Mam nadzieję, że to pomoże:)

 35
Author: Bart Platak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:16:27

PHP ma wbudowaną klasę, ErrorException , do tłumaczeniabłędów PHP na wyjątki, które, jeśli zostaną nieobsługiwane, w naturalny sposób zatrzymałyby wykonywanie.

Wyjątki mają ulepszone mechanizmy obsługi błędów (try catch) i lepsze debugowanie informacji (stack traces).

Umieść to na górze większości ścieżki wykonania (config, lub coś, co jest dołączone jako pierwsze do całego kodu):

 set_error_handler(function($nNumber, $strMessage, $strFilePath, $nLineNumber){
      throw new \ErrorException($strMessage, 0, $nNumber, $strFilePath, $nLineNumber);
 }, /*E_ALL*/ -1);

Chociaż PDO wspiera wyrzucanie wyjątków, jest wyłączony domyślnie musisz ją włączyć:

 $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

Jeśli korzystasz z MySQL, chcesz również, aby błąd nie ustawiał pól obowiązkowych i wielu innych błędów/ostrzeżeń był domyślnie usuwany:

 $pdo->exec("SET sql_mode = 'STRICT_ALL_TABLES'");

Wyjątki mogą być obsługiwane jak w wielu innych językach programowania za pomocą Spróbuj złapać wreszcie :

try
{
    echo $iAmAnUndefinedVariable;
}
catch(\Throwable $exception)
{
    /*[...]*/
}

Podczas walidacji rzeczy, po prostu wyrzuć wyjątki: throw new Exception("Missing URL variable userId!");

Byłoby miło, gdyby PHP zrobił kiedyś czystą przerwę od legacy zgłaszanie błędów i po prostu wyrzucił wyjątki domyślnie (deprecate error_reporting () and change the default).

 6
Author: Tiberiu-Ionuț Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-23 15:49:13

To jest o wiele bardziej eleganckie i czytelne.

try
{

    if($_GET['something'] != 'somevalue') 
    {
        throw new Exception ('something is not a valid value');
    }


    $output .= 'somecode';

    // make a DB query, fetch a row
    //...
    $row = $stmt->Fetch(PDO::ASSOC);

    if($row == null)
    {
        throw new Exception ('the row does not exist.');
    }


    $output .= 'morecode';


    if(somethingIsOK())
    {
        $output .= 'yet more page output';
    }
    else
    {
        throw new Exception ('something is most definitely not OK.');
    }


    echo $output;

}
catch (Exception $e)
{
    echo $e->getMessage();
}
 5
Author: Edson Medina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-14 09:42:36

Używanie try-catch jest jednym z najczystszych rozwiązań, które możesz użyć.

Zrobiłem przykład, który nadal wyświetla nagłówek i stopkę, gdy wystąpi błąd, używając kodu przekonwertowanego do formatu try-catch:

PHP:

<?php
try {
    $output = array();
    if($_GET['something'] != 'somevalue') throw new Exception('something does not have a valid value.');
    $output[] = 'Some Code';
    $row = mt_rand(0, 10) < 5 ? null : mt_rand(0, 100);
    if($row === null) throw new Exception('The row does not exist.');
    $output[] = $row;
    if(!somethingIsOK()) throw new Exception('Something is most definitely not OK.');
    $output[] = 'Yet more page output';
} catch(Exception $e) {
    $output[] = 'Error: ' . $e->getMessage(); // To show output and error
    $output = array('Error: ' . $e->getMessage()); // To only show error
}
function somethingIsOK() {
    return mt_rand(0, 10) < 5;
}
?>

HTML:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8" />
    <title>PHP Error test</title>
    <style type="text/css">
body {
    background: #eee;
    text-align: center
}
#content {
    padding: 60px
}
#header {
    padding: 30px;
    background: #fff
}
#footer {
    padding: 10px;
    background: #ddd
}
    </style>
</head>
<body>
    <div id="header">Header</div>
    <div id="content">
<?php echo implode('<br />', $output); ?>

    </div>
    <div id="footer">Footer</div>
</body>
</html>

Referencje:

 2
Author: uınbɐɥs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-13 00:39:07

Obsługa wyjątków błędów PDO dla zapytań, a tak naprawdę cały kod powinien być uruchamiany:

try{

}

catch{


}

finally{

}

Powodem tego jest to, że znacznie ułatwia debugowanie, gdy można z grubsza wskazać, gdzie w długich skryptach występuje błąd

Więcej informacji tutaj: http://php.net/manual/en/language.exceptions.php

 1
Author: CodeTalk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-12 03:17:37

Utwórz obsługę błędów (set_error_handler) i wrzuć do niej wyjątki.
Pomoże to funkcjom, które nie obsługują WYJĄTKÓW.

 0
Author: Dmitry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-19 01:27:02

Obsłuż poprawnie błąd PHP i ostrzeżenie za pomocą funkcji obsługi błędów. ( Zobacz przykład Tutaj )

Najlepszym sposobem na obsługę błędów w PHP jest, Możesz zatrzymać wszystkie raporty o błędach, dodając tę linię u góry pliku php -

error_reporting(0);

//OR

error_reporting('E_ALL');

// Predefined Constant

Obsługa błędów w PHP przy użyciu funkcji:

  • debug_backtrace-generuje backtrace
  • debug_print_backtrace-wypisuje backtrace
  • error_clear_last-Wyczyść Ostatnie błąd
  • error_get_last-Pobierz ostatni wystąpił błąd
  • error_log-Wyślij komunikat o błędzie do zdefiniowanej obsługi błędów procedury
  • error_reporting-Ustawia, które błędy PHP są zgłaszane
  • restore_error_handler-przywraca poprzednią funkcję obsługi błędów
  • restore_exception_handler-przywraca wcześniej zdefiniowany wyjątek funkcja obsługi
  • set_error_handler-ustawia program obsługi błędów zdefiniowany przez użytkownika function
  • set_exception_handler-Ustawia obsługę wyjątków zdefiniowanych przez użytkownika function
  • trigger_error-generuje komunikat o błędzie/ostrzeżeniu/powiadomieniu na poziomie użytkownika
  • user_error-Alias trigger_error

Wszystkie funkcje wymienione powyżej są używane do obsługi błędów w PHP.

 0
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 06:11:09

Jeśli szukasz struktury kodu, która będzie wyglądać ładnie i będzie działać-możesz użyć metody whitelist, której zawsze używam. Na przykład-Walidacja zmiennej $_GET:

$error = false;

if(!isset($_GET['var'])) 
{
    $error = 'Please enter var\'s value';
}
elseif(empty($_GET['var'])) 
{
    $error = 'Var shouldn\'t be empty';
}
elseif(!ctype_alnum($_GET['var'])) 
{
    $error = 'Var should be alphanumeric';
}

//if we have no errors -> proceed to db part
if(!$error) 
{
    //inserting var into database table
}

Więc to jest to, tylko 2 if/elseif bloki, bez zagnieżdżania

 -3
Author: Noobie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-17 00:35:30