Могу ли я попробовать / поймать предупреждение?

мне нужно поймать некоторые предупреждения, брошенные из некоторых собственных функций php, а затем обработать их.

в частности:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )

он выдает предупреждение при сбое DNS-запроса.

try/catch не работает, потому что предупреждение не является исключением.

теперь у меня есть 2 варианта:

  1. set_error_handler кажется излишним, потому что я должен использовать его для фильтрации каждого предупреждения на странице (это правда?);

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

какая здесь лучшая практика?

10 ответов


установить и восстановить обработчик ошибок

одна возможность-установить свой собственный обработчик ошибок перед вызовом и восстановить предыдущий обработчик ошибок позже с restore_error_handler().

set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();

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

set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();

превращение ошибок в исключения

можно использовать set_error_handler() и ErrorException класс, чтобы превратить все ошибки php в исключения.

set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    dns_get_record();
} catch (ErrorException $e) {
    // ...
}

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

подавление предупреждения

другая возможность подавить позвоните с оператором @ и проверьте возвращаемое значение dns_get_record() далее. но я бы не советовал этого поскольку ошибки / предупреждения запускаются для обработки, а не подавляются.


решение, которое действительно работает, оказалось установкой простого обработчика ошибок с , например:

set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();

function warning_handler($errno, $errstr) { 
// do something
}

будьте осторожны с @ оператор - в то время как он подавляет предупреждения, он также подавляет фатальные ошибки. Я потратил много времени на отладку проблема в системе, где кто-то написал @mysql_query( '...' ) и проблема заключалась в том, что поддержка mysql не была загружена в PHP, и это вызвало тихую фатальную ошибку. Это будет безопасно для тех вещей, которые являются частью ядра PHP, но пожалуйста используйте его с осторожностью.

[email protected]:~$ php -a
Interactive shell

php > echo @something(); // this will just silently die...

нет дальнейшего вывода - удачи отладки это!

[email protected]:~$ php -a
Interactive shell

php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error:  Call to undefined function something() in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
[email protected]:~$ 

на этот раз мы видим, почему это не удалось.


Я хотел попробовать / поймать предупреждение, но в то же время сохранить обычное предупреждение/регистрацию ошибок (например, в /var/log/apache2/error.log); для которого обработчик должен вернуть false. Однако, начиная с "броска нового"..."оператор в основном прерывает выполнение, затем нужно сделать трюк" wrap in function", также обсуждаемый в:

есть ли статический способ бросить исключение в php

или, вкратце:

  function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
  }
  function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
    return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
    # error_log("AAA"); # will never run after throw
    /* Do execute PHP internal error handler */
    # return false; # will never run after throw
  }
  ...
  set_error_handler('warning_handler', E_WARNING);
  ...
  try {
    mkdir($path, 0777, true);
  } catch (Exception $e) {
    echo $e->getMessage();
    // ...
  }

EDIT: после более близкого осмотра, оказывается, это не работает:"return false && throwErrorException ..." будет, в основном, не бросьте исключение и просто войдите в журнал ошибок; удаление"false &&" части, как в "return throwErrorException ...", сделает исключение бросая работу, но после этого не войдет в error_log... Я бы все равно держал это в курсе, хотя, поскольку я не видел, чтобы это поведение документировалось в другом месте.


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


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


Если dns_get_record() не удается, он должен вернуться FALSE, Так что вы можете подавить предупреждение с @ и затем проверить возвращаемое значение.


объединение этих строк кода вокруг file_get_contents() вызов внешнего url-адреса помог мне обрабатывать предупреждения, такие как"не удалось открыть поток: время ожидания соединения истекло" гораздо лучше:

set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
    throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
    $iResult = file_get_contents($sUrl);
} catch (Exception $e) {
    $this->sErrorMsg = $e->getMessage();
}
restore_error_handler();

Это решение также работает в контексте объекта. Вы можете использовать его в функции:

public function myContentGetter($sUrl)
{
  ... code above ...
  return $iResult;
}

попробуйте проверить, возвращает ли он некоторое логическое значение, тогда вы можете просто поставить его в качестве условия. Я столкнулся с этим с oci_execute(...) который возвращал некоторые нарушения с моими уникальными ключами.

ex.
oci_parse($res, "[oracle pl/sql]");
if(oci_execute){
...do something
}

Я бы рекомендовал использовать @ только для подавления предупреждений, когда это прямая операция (например, $prop = @($high/($width - $depth)); пропустить деление на ноль предупреждений). Однако в большинстве случаев с этим лучше справиться.