Подтвердить что ты не робот

Лучший способ обработки ошибок на 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-страницу? Я не хочу просто умирать с пустым экраном, так как это было бы очень неприхотливым для пользователя, но вместо этого нужно выводить сообщение в теле страницы, все еще позволяя показывать верхний и нижний колонтитулы.

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

4b9b3361

Ответ 1

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

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

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

Для фатальные ошибки Я предпочитаю использовать исключения (с блоками 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();
}

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

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

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

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

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

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

Надеюсь, что это поможет:)

Ответ 2

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
{
    echo $iAmAnUndefinedVariable;
}
catch(\Throwable $exception)
{
    /*[...]*/
}

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

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

Ответ 3

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

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

Ответ 4

Использование 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>

Литература:

Ответ 5

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

try{

}

catch{


}

finally{

}

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

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

Ответ 6

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

Ответ 7

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

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

error_reporting(0);

//OR

error_reporting('E_ALL');

// Predefined Constant

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

  • debug_backtrace - создает обратную трассировку
  • debug_print_backtrace - печатает 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.

Ответ 8

Если вы ищете структуру кода, которая будет выглядеть красиво и будет работать - вы можете использовать метод whitelist, который я всегда использую. Например - проверка переменной $_GET:

$error = false;

if(!isset($_GET['var'])) 
{
    $error = 'Please enter var\ 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 блоков, без вложенности