Лучший способ обработки ошибок на php-странице?

Сейчас мои страницы выглядят примерно так:

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 } 

То, как я делаю все, работает, но это очень громоздко и утомительно для того, что, вероятно, очевидно: предположим, что я вызываю функцию где-то посередине моего кода или хочу проверить значение переменной или проверить запрос БД вернул действительный результат, и если он сбой, я хочу вывести ошибку? Я должен был бы сделать еще один if / else блок и переместить весь код внутри нового блока if. Это не похоже на умный способ делать что-то.

Я читал о try / catch и думал о том, чтобы поместить весь мой код внутри инструкции try, а затем пусть код запускается без каких-либо блоков if / else, и если что-то не удается просто выбросить исключение. Из того, что я прочитал, это остановит выполнение и заставит его перейти прямо к блоку catch (точно так же, как неудачный оператор if перейдет в блок else), где я мог бы вывести сообщение об ошибке. Но является ли это приемлемой или стандартной практикой?

Каков наилучший способ обработки ошибок, фатальных или нет, в php-приложении, которое создает и выводит HTML-страницу? Я не хочу просто умирать с пустым экраном, так как это было бы очень неприхотливым для пользователя, но вместо этого хотелось бы выводить сообщение в теле страницы, все еще позволяя показывать верхний и нижний колонтитулы.

Спасибо за ваш совет!

Есть много способов, которыми вы можете справиться с этим, и, честно говоря, ни один из них не является по сути «правильным».

Вам придется решить для себя, какой метод более «удобен» для вас – это всегда манера предпочтений (хотя есть определенные методы, которых вам следует избегать и по уважительным причинам).

Это будет сильно зависеть от того, как вы разделите свою логику, однако я склонен заключать весь код, который может возвращать нефатальные ошибки внутри функции, и использовать возвращаемое значение указанной функции, чтобы указать на наличие ошибки.

Для фатальных ошибок я использую исключения (с блоками try-catch ).

Теперь, чтобы быть ясным:

  • Нефатальная ошибка – это ошибка, которую вы можете восстановить – это означает, что, хотя что-то пошло не так, есть еще какой-то код, который может быть выполнен и генерировать некоторый ценный вывод. Например, если вы хотите получить текущее время с использованием протокола NTP , но сервер не ответил, вы можете решить использовать локальную функцию time и по-прежнему отображать некоторые ценные данные для пользователя.
  • Неустранимая ошибка – это ошибка, из-за которой вы не сможете ее восстановить – это означает, что произошло что-то действительно плохое, и единственное, что вы можете сделать, это сообщить вашему пользователю, что страница не может делать то, о чем просили. Например, если вы извлекли некоторые данные из своей базы данных и получили SQL Exception – нет никаких ценных данных, которые будут показаны, и вы можете сообщить об этом только пользователю.

Нефатальные ошибки (с использованием возврата функции)

Хорошим примером использования функций-возвратов в качестве способа решения проблем, не связанных со смертельным исходом, была бы функция, которая пытается отображать содержимое какого-либо файла на странице, если это не главная цель страницы (например, вы бы функция, которая отображает значки, извлекаемые из текстового файла, на каждой странице – я знаю, что это далека, но неся со мной).

 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 .. 

Фактически, функция fopen сама по себе является примером этого – она вернется .

Возвращает ресурс указателя файла при успешном выполнении или FALSE при ошибке.


Fatal-Errors (с использованием исключений – try-catch)

Когда у вас есть часть кода, которая должна быть выполнена, потому что это именно то, чего хотел пользователь (например, считывая все новости из базы данных и отображая их пользователю), вы можете использовать исключения. Возьмем простой пример: пользователь посетил его профиль и захотел увидеть все полученные ему сообщения (предположим, что на данный момент они хранятся в виде простого текста). У вас может быть такая функция, как:

 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; } 

И используйте его вот так:

 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(); } 

Теперь это может пригодиться, если у вас есть сценарий «верхнего уровня», который будет выполнять весь другой код. Это означает, что, например, в вашем index.php вас просто будет:

 try{ .. execute some code, perform some functions .. } catch(Exception $e){ echo "Sorry, there was an error: ".$e->getMessage(); } 

Не злоупотребляйте исключениями!

Независимо от того, что вы делаете, никогда не используйте исключения, чтобы проверить, что вы можете восстановить. Прочтите по другому вопросу (полный кредит принадлежит Антону Гоголеву за очень хорошее объяснение этому, а также другие ответчики) о том, почему это так.

дальнейшее чтение

Теперь нет лучшего способа узнать, как справляться с ошибками, чем попробовать несколько вещей и посмотреть, что хорошо для вас. Вы можете найти ниже полезное:

  • W3School на PHP Обработка исключений
  • Краткое руководство по обработке ошибок (подобно методу my-return)
  • Обширный учебник по обработке ошибок PHP, в том числе с использованием функции trigger_error() , о которой я не упоминал, потому что я не использую его и мало знаю об этом, но, по-видимому, он действительно полезен. Это особенно хорошо читается.

Надеюсь это поможет 🙂

Это намного элегантнее и удобочитаемо.

 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(); } 

PHP имеет встроенный класс ErrorException для преобразования ошибок PHP в исключения, которые, если они необработаны, естественно прекратили выполнение.

Исключения улучшили механизмы обработки ошибок (try catch) и лучшую информацию об отладке (трассировки стека).

Включите это в начало большей части вашего пути выполнения (config или что-то, что включено сначала со всем вашим кодом):

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

Хотя PDO поддерживает исключение для исключения, он отключен по умолчанию, вы должны включить его:

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

Если вы используете MySQL, вы также хотите, чтобы ошибка не устанавливала обязательные поля и многие другие ошибки / предупреждения, которые были прощены по умолчанию:

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

Исключения можно обрабатывать, как и во многих других языках программирования, используя try catch finally :

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

При проверке материала просто бросайте исключения: throw new Exception("Missing URL variable userId!");

Было бы неплохо, если бы PHP сделал чистую перерыв когда-нибудь из устаревшей информации об ошибках и просто выбросил исключения по умолчанию (deprecate error_reporting () и изменил значение по умолчанию).

Использование try-catch – одно из самых чистых решений, которое вы можете использовать.

Я привел пример, который по-прежнему отображает верхний и нижний колонтитулы при возникновении ошибки, используя код, преобразованный в формат 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> 

Рекомендации:

  • PHP: Исключения – Руководство
  • PHP: CATCH – Руководство

Обработка ошибок ошибок PDO для запросов, и действительно весь код должен быть запущен через:

 try{ } catch{ } finally{ } 

Причина этого заключается в том, что упростить отладку, когда вы можете точно определить, где в длинных сценариях возникает ошибка

подробнее здесь: http://php.net/manual/en/language.exceptions.php

Создайте обработчик ошибок (set_error_handler) и исключите исключения из него.
Это поможет для функций, которые не поддерживают исключения.

Обрабатывайте ошибки и предупреждения PHP правильно, используя функции обработки ошибок. (См. Пример здесь )

Лучший способ обработки ошибок в PHP – это остановить все сообщения об ошибках, добавив эту строку в верхнюю часть вашего php-файла –

 error_reporting(0); //OR error_reporting('E_ALL'); // Predefined Constant 

Обработка ошибок в PHP с использованием функций:

  • debug_backtrace – создает обратную линию
  • debug_print_backtrace – печатает обратную линию
  • error_clear_last – очистить самую последнюю ошибку
  • error_get_last – получить последнюю произошедшую ошибку
  • error_log – отправить сообщение об ошибке в определенные процедуры обработки ошибок
  • error_reporting – устанавливает, какие ошибки PHP сообщаются
  • restore_error_handler – восстанавливает предыдущую функцию обработчика ошибок
  • restore_exception_handler – восстанавливает ранее определенную функцию обработчика исключений
  • set_error_handler – устанавливает пользовательскую функцию обработчика ошибок
  • set_exception_handler – устанавливает пользовательскую функцию обработчика исключений
  • trigger_error – генерирует сообщение об ошибке / предупреждении / уведомлении на уровне пользователя
  • user_error – Псевдоним trigger_error

Все функции, перечисленные выше, используются для обработки ошибок в PHP.

Если вы ищете структуру кода, которая будет выглядеть красиво и будет работать – вы можете использовать метод « whitelist который я всегда использую. Например – проверка переменной $_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 } 

Итак, это все, всего 2 блока if/elseif , без вложенности