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

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

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

Установка и восстановление обработчика ошибок

Одна из возможностей – установить свой собственный обработчик ошибок перед вызовом и восстановить предыдущий обработчик ошибок позже с помощью 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() . Но я бы посоветовал это сделать, поскольку ошибки / предупреждения запускаются для обработки, а не для подавления.

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

 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, но, пожалуйста, используйте его с осторожностью.

 bob@mypc:~$ php -a Interactive shell php > echo @something(); // this will just silently die... 

Никаких дополнительных результатов – удачи отладки!

 bob@mypc:~$ 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 bob@mypc:~$ 

На этот раз мы можем понять, почему это не удалось.

Я хотел попробовать / поймать предупреждение, но в то же время сохранить обычное предупреждение / журнал ошибок (например, в /var/log/apache2/error.log ); для которого обработчик должен вернуть false . Однако, поскольку оператор «throw new …» в основном прерывает выполнение, тогда необходимо выполнить трюк «wrap into 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 ... выясняется, что это не сработает: « return false && throwErrorException ... », в основном, не будет генерировать исключение и просто зарегистрировать журнал ошибок; удалив часть « false && », как в « return throwErrorException ... », сделает работу по return throwErrorException ... исключений, но затем не войдет в журнал error_log … Я все равно оставил бы это в курсе, хотя я, Такое поведение было зафиксировано в других местах.

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

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

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

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

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

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