web-dev-qa-db-fra.com

Supprimer l'erreur avec l'opérateur @ dans PHP

À votre avis, est-il toujours valide d'utiliser l'opérateur @ pour supprimer une erreur/un avertissement dans PHP alors que vous êtes en train de gérer l'erreur?

Si oui, dans quelles circonstances l'utiliseriez-vous?

Les exemples de code sont les bienvenus.

Edit: Note aux réplicateurs. Je ne cherche pas à désactiver le signalement des erreurs, mais, par exemple, la pratique courante consiste à utiliser

@fopen($file);

et ensuite vérifier après ... mais vous pouvez vous débarrasser de la @ en faisant

if (file_exists($file))
{
    fopen($file);
}
else
{
    die('File not found');
}

ou similaire. 

Je suppose que la question est la suivante: y at-il un endroit où @ DOIT être utilisé pour supprimer une erreur, qui NE PEUT PAS être traité autrement?

65
Mez

Je voudrais supprimer l'erreur et le gérer . Sinon, vous risquez d'avoir un problèmeTOCTOU(Heure de vérification, heure d'utilisation. Par exemple, un fichier peut être supprimé après que file_exists renvoie la valeur true, mais avant la fin de l'opération).

Mais je ne supprimerais pas simplement les erreurs pour les faire disparaître. Ceux-ci feraient mieux d'être visibles.

24
Paweł Hajdan

Note: Tout d'abord, je réalise que 99% des développeurs de PHP utilisent l'opérateur de suppression des erreurs (j'étais l'un d'entre eux), je m'attends donc à ce que tout PHP qui voit cela ne soit pas d'accord.

À votre avis, est-il toujours valide d'utiliser l'opérateur @ pour supprimer une erreur/un avertissement dans PHP alors que vous êtes peut-être en train de gérer l'erreur?

Réponse courte:
Non!

Réponse plus longue et correcte:
Je ne sais pas car je ne sais pas tout, mais je n’ai pas encore trouvé de solution satisfaisante.

Pourquoi c'est mauvais:
Depuis environ sept ans, je pense à l’utilisation de PHP et j’ai vu une agonie sans fin de débogage causée par l’opérateur de suppression d’erreur et je n’ai jamais rencontré de situation où cela était inévitable.

Le problème est que l'élément de code pour lequel vous supprimez des erreurs peut actuellement uniquement provoquer l'erreur que vous voyez. Toutefois, lorsque vous modifiez le code utilisé par la ligne supprimée ou l'environnement dans lequel elle s'exécute, il est fort probable que la ligne tente de générer une erreur complètement différente de celle que vous tentiez d'ignorer. Alors comment retrouver une erreur qui ne sort pas? Bienvenue au débogage de l'enfer!

Il m'a fallu de nombreuses années pour réaliser combien de temps je perdais tous les deux mois à cause d'erreurs supprimées. Le plus souvent (mais pas exclusivement), c'était après l'installation d'un script/application/bibliothèque tiers qui était exempt d'erreur dans l'environnement des développeurs, mais pas le mien en raison d'une différence de configuration php ou serveur ou d'une dépendance manquante qui aurait normalement normalement généré une erreur immédiatement alerter sur le problème, mais pas lorsque le dev ajoute la magie @.

Les alternatives (en fonction de la situation et du résultat souhaité):
Traitez l'erreur réelle dont vous êtes conscient, de sorte que si un morceau de code va provoquer une certaine erreur, il ne sera pas exécuté dans cette situation particulière. Mais je pense que vous avez compris cette partie et que vous craigniez que les utilisateurs finaux ne voient des erreurs, ce que je vais maintenant aborder.

Pour les erreurs courantes, vous pouvez configurer un gestionnaire d'erreurs de sorte qu'il soit sorti comme vous le souhaitez lorsque vous visualisez la page, mais masqué des utilisateurs finaux et enregistré pour que vous sachiez quelles erreurs vos utilisateurs ont déclenchées.

Pour les erreurs irrécupérables, désactivez display_errors (votre gestionnaire d'erreurs est toujours déclenché) dans votre fichier php.ini et activez la journalisation des erreurs. Si vous avez un serveur de développement et un serveur actif (ce que je recommande), cette étape n'est pas nécessaire sur votre serveur de développement. Vous pouvez donc toujours déboguer ces erreurs fatales sans avoir à consulter le fichier journal des erreurs. Il y a même un astuce utilisant la fonction d'arrêt pour envoyer beaucoup d'erreurs fatales à votre gestionnaire d'erreurs.

En résumé:
S'il vous plaît, évitez-le. Il y a peut-être une bonne raison à cela, mais je n’en ai pas encore vu un, donc jusqu’à ce jour, j’estime que l’opérateur (@) de suppression d’erreurs est mauvais.

Vous pouvez lire mon commentaire sur la page des opérateurs de contrôle d'erreur dans le manuel PHP si vous souhaitez plus d'informations.

113
Gerry

Oui, la suppression a du sens.

Par exemple, la commande fopen() renvoie FALSE si le fichier ne peut pas être ouvert. Bien, mais aussi génère un message d’avertissement PHP. Souvent, vous ne voulez pas l'avertissement - vous vérifierez vous-même FALSE.

En fait, le manuel PHP suggère spécifiquement d'utiliser @ dans ce cas!

19
Jason Cohen

Si vous ne souhaitez pas qu'un avertissement soit émis lors de l'utilisation de fonctions telles que fopen (), vous pouvez supprimer l'erreur mais utiliser des exceptions:

try {
    if (($fp = @fopen($filename, "r")) == false) {
        throw new Exception;
    } else {
        do_file_stuff();
    }
} catch (Exception $e) {
    handle_exception();
}
12
dirtside

La suppression d'erreur doit être évitée sauf si vous savez que vous pouvez gérer toutes les conditions. 

Cela peut être beaucoup plus difficile qu'il n'y paraît au début. 

Ce que vous devez vraiment faire est de vous fier à "error_log" de PHP comme méthode de reporting, car vous ne pouvez pas vous fier aux utilisateurs qui consultent des pages pour signaler des erreurs. (Et vous devriez aussi désactiver php d'afficher ces erreurs) 

Alors au moins, vous aurez un rapport complet sur tout ce qui ne va pas dans le système. 

Si vous devez réellement gérer les erreurs, vous pouvez créer un gestionnaire d’erreurs personnalisé. 

http://php.net/set-error-handler

Ensuite, vous pouvez éventuellement envoyer des exceptions (qui peuvent être gérées) et faire tout ce qui est nécessaire pour signaler des erreurs étranges à l’administration. 

6
Kent Fredric

Je ne me permets jamais d'utiliser '@' ... point.

Lorsque je découvre l'utilisation de '@' dans le code, j'ajoute des commentaires pour la rendre plus évidente, à la fois au moment de l'utilisation et dans le docblock autour de la fonction où elle est utilisée. J'ai moi aussi été mordu par le "débogage à la recherche d'un fantôme" en raison de ce type de suppression d'erreur, et j'espère faciliter la tâche à la prochaine personne en soulignant son utilisation lorsque je la trouverai.

Dans les cas où je souhaite que mon propre code génère une exception si une fonction native PHP rencontre une erreur et que "@" semble être le moyen le plus simple à suivre, j'ai plutôt choisi de faire quelque chose même résultat mais est (encore) flagrant dans le code:

$orig = error_reporting(); // capture original error level
error_reporting(0);        // suppress all errors
$result = native_func();   // native_func() is expected to return FALSE when it errors
error_reporting($orig);    // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }

C'est beaucoup plus de code qu'il suffit d'écrire:

$result = @native_func();

mais je préfère rendre ma suppression très nécessaire, au nom de la pauvre âme de débogage qui me suit.

6
ashnazg

La plupart des gens ne comprennent pas la signification du message d'erreur.
Sans blague. La plupart d'entre eux.

Ils pensent que les messages d'erreur sont tous les mêmes, dit "Quelque chose ne va pas!"
Ils ne se donnent pas la peine de le lire.
Bien que ce soit la partie la plus importante du message d'erreur - pas seulement le fait qu'il ait été soulevé, mais sa signification. Cela peut vous dire que quoi va mal. Les messages d'erreur sont une aide, pas pour vous déranger avec "comment le cacher?" problème. C'est l'un des plus grands malentendus du monde de la programmation Web pour débutants. 

Ainsi, au lieu de bâillonner le message d'erreur, on devrait lire ce qu'il dit. Il n'a pas qu'une seule valeur "fichier non trouvé". Il peut y avoir des milliers d’erreurs différentes: permission denied, save mode restriction, open_basedir restriction etc.etc. Chacun nécessite une action appropriée. Mais si vous le bâillonnez, vous ne saurez jamais ce qui s'est passé!

Le PO commet une erreur un rapport avec une erreur une manipulation , alors que c'est une très grande différence!
Le traitement des erreurs est pour l'utilisateur. "quelque chose est arrivé" est suffisant ici.
Bien que le signalement des erreurs s’adresse aux programmeurs, ceux-ci ont désespérément besoin de savoir ce qui s’est passé. 

Ainsi, ne gagez jamais les messages d'erreur. Les deux le consignent pour le programmeur et le manipulent pour l'utilisateur.

5

Le seul endroit où j'ai vraiment besoin de l'utiliser est la fonction eval. Le problème avec eval est que, lorsque la chaîne ne peut pas être analysée en raison d’une erreur de syntaxe, eval ne renvoie pas false, mais renvoie une erreur, comme si une erreur d’analyse était exécutée dans le script normal. Afin de vérifier si le script stocké dans la chaîne est analysable, vous pouvez utiliser quelque chose comme:

$script_ok = @eval('return true; '.$script);

Autant que je sache, c’est la manière la plus élégante de le faire.

3
Milan Babuškov

Utiliser @ est parfois contre-productif. D'après mon expérience, vous devriez toujours désactiver le rapport d'erreurs dans le fichier php.ini ou appeler

error_reporting(0);

sur un site de production. Ainsi, lorsque vous êtes en développement, vous pouvez simplement commenter la ligne et garder les erreurs visibles pour le débogage. 

3
Eric Lamb

n'y a-t-il pas moyen de supprimer du php.ini les avertissements et les erreurs? dans ce cas, vous pouvez déboguer uniquement en changeant un indicateur et en ne cherchant pas à découvrir lequel @ cache le problème.

3
Enrico Murru

Un endroit que j'utilise est le code de socket, par exemple, si vous avez un délai d'attente défini, vous recevrez un avertissement à ce sujet si vous n'incluez pas @, même s'il est correct de ne pas recevoir de paquet.

$data_len = @socket_recvfrom( $sock, $buffer, 512, 0, $remote_Host, $remote_port )
2
Don Neufeld

Vous ne voulez pas tout supprimer, car cela ralentit votre script.

Et oui, il existe un moyen à la fois dans php.ini et dans votre script de supprimer les erreurs (mais ne le faites que lorsque vous êtes dans un environnement réel et que vous enregistrez vos erreurs depuis php)

<?php
    error_reporting(0);
?>

Et vous pouvez lire this pour la version php.ini de la désactiver.

1
Ólafur Waage

Si vous utilisez une fonction de gestion des erreurs personnalisée et souhaitez supprimer une erreur (probablement une erreur connue), utilisez cette méthode. L'utilisation de '@' n'est pas une bonne idée dans ce contexte car elle ne supprimera pas l'erreur si le gestionnaire d'erreurs est défini.

Écrivez 3 fonctions et appelez comme ceci. 

# supress error for this statement
supress_error_start();  
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.  

function supress_error_start(){
    set_error_handler('nothing');
    error_reporting(0);
}

function supress_error_end(){
    set_error_handler('my_err_handler');
    error_reporting('Set this to a value of your choice');
}

function nothing(){ #Empty function
}

function my_err_handler('arguments will come here'){
      //Your own error handling routines will come here
}
0
Sumesh

Aujourd'hui, j'ai rencontré un problème qui était un bon exemple de la possibilité d'utiliser au moins temporairement l'opérateur @.

En résumé, j'ai trouvé des informations de connexion (nom d'utilisateur et mot de passe en texte brut) inscrites dans la trace du journal des erreurs.

Voici un peu plus d'informations sur ce problème.

La logique de connexion appartient à une classe à part, car le système est censé offrir différents mécanismes de connexion. En raison de problèmes de migration de serveur, une erreur s'est produite. Cette erreur a vidé toute la trace dans le journal des erreurs, y compris les informations sur le mot de passe! Une méthode prévoyait le nom d'utilisateur et le mot de passe en tant que paramètres. C'est pourquoi trace a tout écrit fidèlement dans le journal des erreurs.

La solution à long terme consiste ici à refactoriser ladite classe, au lieu d'utiliser nom d'utilisateur et mot de passe en tant que 2 paramètres, par exemple en utilisant un seul paramètre de tableau contenant ces 2 valeurs (trace écrira Array pour le paramètre dans de tels cas). Il existe également d'autres moyens de s'attaquer à ce problème, mais il s'agit d'un tout autre problème. 

Quoi qu'il en soit. Les messages de trace sont utiles, mais dans ce cas, ils sont carrément nuisibles.

La leçon que j’ai apprise dès que j’ai remarqué cette sortie de trace: supprimer parfois un message d’erreur constitue pour le moins une mesure utile d’espacement afin d’éviter des dommages supplémentaires.

À mon avis, je ne pensais pas que c'était un cas de mauvaise conception de classe. L'erreur elle-même a été déclenchée par une exception PDOException (problème d'horodatage déplaçant de MySQL 5.6 à 5.7) qui vient d'être vidée par PHP par défaut, tout dans le journal des erreurs.

En général, je n'utilise pas l'opérateur @ pour toutes les raisons expliquées dans d'autres commentaires, mais dans ce cas, le journal des erreurs m'a convaincu de faire quelque chose rapidement jusqu'à ce que le problème soit correctement résolu.

0
Herbert Peters