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ę!
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 localtime
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:
- W3School na PHP Exception obsługa
- krótki tutorial o obsłudze błędów (podobny do mojej metody function-returns)
-
obszerny samouczek na temat obsługi błędów PHP - w tym używania funkcji
trigger_error()
, o której nie wspomniałem, ponieważ jej nie używam i niewiele o niej wiem, ale najwyraźniej jest naprawdę przydatna. to jest szczególnie dobra lektura.
Mam nadzieję, że to pomoże:)
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).
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();
}
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:
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
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.
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.
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
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