web-dev-qa-db-fra.com

Puis-je essayer/attraper un avertissement?

Je dois attraper quelques avertissements émis par certaines fonctions natives php, puis les gérer.

Plus précisément:

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

Il envoie un avertissement lorsque la requête DNS échoue.

try/catch ne fonctionne pas car un avertissement n'est pas une exception.

J'ai maintenant 2 options:

  1. set_error_handler semble exagéré, car je dois l'utiliser pour filtrer tous les avertissements de la page (est-ce vrai?);

  2. Ajustez le signalement/l'affichage des erreurs afin que ces avertissements ne soient pas répercutés à l'écran, puis vérifiez la valeur de retour; si c'est false, aucun enregistrement n'est trouvé pour le nom d'hôte.

Quelle est la meilleure pratique ici?

307
user121196

Définir et restaurer le gestionnaire d'erreurs

Une possibilité consiste à définir votre propre gestionnaire d'erreurs avant l'appel et à restaurer ultérieurement le gestionnaire d'erreurs précédent avec restore_error_handler().

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

Vous pouvez développer cette idée et écrire un gestionnaire d'erreurs réutilisable qui enregistre les erreurs pour vous.

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

Transformer les erreurs en exceptions

Vous pouvez utiliser set_error_handler() et la classe ErrorException pour transformer toutes les erreurs php en exceptions.

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) {
    // ...
}

Lorsque vous utilisez votre propre gestionnaire d'erreurs, il est important de noter qu'il contournera le paramètre error_reporting et transmettra toutes les erreurs (notifications, avertissements, etc.) à votre gestionnaire d'erreurs. Vous pouvez définir un second argument sur set_error_handler() pour définir les types d'erreur que vous souhaitez recevoir ou accéder au paramètre actuel à l'aide de ... = error_reporting() dans le gestionnaire d'erreurs.

Suppression de l'avertissement

Une autre possibilité consiste à supprimer l'appel avec l'opérateur @ et à vérifier la valeur de retour de dns_get_record() par la suite. Mais je déconseillerais cela car des erreurs/avertissements sont déclenchés pour être traités et non supprimés.

332
Philippe Gerber

La solution qui fonctionne vraiment s’est avérée être de définir un gestionnaire d’erreurs simple avec le paramètre E_WARNING, comme ceci:

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

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

Faites attention avec l'opérateur @- s'il supprime les avertissements, il supprime également les erreurs fatales. J'ai passé beaucoup de temps à déboguer un problème dans un système où quelqu'un avait écrit @mysql_query( '...' ) et le problème était que le support mysql n'était pas chargé dans PHP et que cela provoquait une erreur fatale silencieuse. Ce sera sans danger pour les choses qui font partie du noyau PHP mais s'il vous plaît, utilisez-le avec précaution.

bob@mypc:~$ php -a
Interactive Shell

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

Pas d'autre sortie - bonne chance pour le débogage!

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:~$ 

Cette fois, nous pouvons voir pourquoi cela a échoué.

27
GuruBob

Je voulais essayer/attraper un avertissement, mais garder en même temps la journalisation habituelle des avertissements/erreurs (par exemple, dans /var/log/Apache2/error.log); pour lequel le gestionnaire doit renvoyer false. Cependant, étant donné que l'instruction "throw new ..." interrompt fondamentalement l'exécution, il faut alors exécuter l'astuce "wrap in function", également décrite dans: 

Existe-t-il un moyen statique de créer une exception en php

Ou, en bref:

  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: après une inspection plus minutieuse, il s’avère que cela ne fonctionne pas: le "return false && throwErrorException ..." va, en gros, not renvoyer l’exception et se connecter dans le journal des erreurs; supprimer la partie "false &&", comme dans "return throwErrorException ...", fera fonctionner l'exception, mais ne se connectera pas ensuite à error_log ... Je garderais quand même ce message, cependant je n'ai pas vu ce comportement documenté autre part.

5
sdaau

Vous devriez probablement essayer de vous débarrasser complètement de l'avertissement, mais si cela n'est pas possible, vous pouvez préfixer l'appel avec @ (c'est-à-dire @dns_get_record (...)), puis utiliser toutes les informations que vous pouvez obtenir pour déterminer si l'avertissement est arrivé ou pas.

4
rpjohnst

La combinaison de ces lignes de code autour d'un appel file_get_contents() vers une URL externe m'a aidée à gérer des avertissements tels que " impossible d'ouvrir le flux: Connexion expirée " beaucoup mieux:

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

Cette solution fonctionne également dans le contexte de l'objet. Vous pouvez l'utiliser dans une fonction:

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

Normalement, vous ne devriez jamais utiliser @ à moins que ce ne soit la seule solution. Dans ce cas spécifique, la fonction dns_check_record doit être utilisée en premier pour savoir si l’enregistrement existe.

3
florynth

Si dns_get_record() échoue, il devrait renvoyer FALSE afin que vous puissiez supprimer l'avertissement avec @, puis vérifier la valeur de retour.

2
Amber

essayez de vérifier si elle retourne une valeur booléenne, vous pouvez simplement la poser comme condition. J'ai rencontré cela avec le oci_execute (...) qui renvoyait une violation avec mes clés uniques.

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