Question

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

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

Les exemples de code sont les bienvenus.

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

@fopen($file);

puis vérifiez après ... mais vous pouvez vous débarrasser du @ 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?

Était-ce utile?

La solution

Je supprimerais l'erreur et la gérerais . Sinon, vous risquez de rencontrer un problème TOCTOU (Heure de vérification, heure d'utilisation. Par exemple, un fichier peut être supprimé après que file_exists ait renvoyé la valeur true, mais avant la fin du processus).

Mais je ne supprimerais pas simplement les erreurs pour les faire disparaître. Celles-ci devraient être mieux visibles.

Autres conseils

Note: Tout d'abord, je réalise que 99% des développeurs PHP utilisent l'opérateur de suppression des erreurs (je faisais partie de ceux-là), je m'attends donc à ce que tous les développeurs PHP voient cela en désaccord.

  

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

Réponse courte:
Non!

Une réponse plus longue, plus 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:
En ce qui me semble être environ 7 ans d’utilisation de PHP, j’ai vu une agonie de débogage sans fin causée par l’opérateur de suppression d’erreurs et je n’ai jamais rencontré de situation qui était inévitable.

Le problème est que l'élément de code pour lequel vous supprimez des erreurs ne peut actuellement provoquer que l'erreur que vous voyez. Toutefois, lorsque vous modifiez le code sur lequel repose la ligne supprimée ou l'environnement dans lequel elle s'exécute, il est alors possible 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'erreurs 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 élément 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 cela et que vous craigniez que les utilisateurs finaux ne voient des erreurs, ce que je vais maintenant aborder.

Pour les erreurs habituelles, vous pouvez configurer un gestionnaire d’erreur de sorte qu’il soit affiché comme vous le souhaitez lorsque vous visualisez la page, mais masqué des utilisateurs finaux et consigné afin que vous sachiez quelles erreurs vos utilisateurs déclenchent.

Pour les erreurs fatales, 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 disposez d'un serveur de développement et d'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 existe même une utilisation de la fonction d'arrêt pour envoyez de nombreuses 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 des erreurs dans le manuel PHP si vous le souhaitez. plus d'infos.

Oui, la suppression a du sens.

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

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

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

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

Lorsque je découvre l'utilisation de '@' dans le code, j'ajoute des commentaires pour le rendre plus évident, à la fois au moment de l'utilisation et dans le docblock autour de la fonction où il est utilisé. Moi aussi, j'ai été piqué par "chasser un fantôme". le débogage 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 trouve.

Dans les cas où je souhaite que mon propre code génère une exception si une fonction PHP native rencontre une erreur et que "@" semble être le moyen le plus simple, je choisis plutôt de faire quelque chose d'autre qui obtient le même résultat. 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. Pour le bien de la pauvre âme de débogage qui me suit.

La suppression des erreurs doit être évitée à moins que vous sachiez que vous pouvez gérer toutes les conditions.

Cela risque d’être beaucoup plus difficile qu’il n’apparaît au début.

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

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.

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 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 que cela ait été soulevé, mais sa signification. Cela peut vous dire ce qui 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 gagging le message d'erreur, on devrait lire ce qu'il dit. Il ne contient pas seulement un " fichier non trouvé " valeur. Il peut y avoir des milliers d’erreurs différentes: permission refusée , restriction de mode d’enregistrement , restriction open_basedir 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 génère une erreur de rapport avec une gestion d'erreur , alors que c'est une très grande différence!
La gestion des erreurs est pour l'utilisateur. "quelque chose est arrivé" est suffisant ici.
Bien que le signalement des erreurs soit destiné 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. enregistrez-le pour le programmeur et gérez-le pour l'utilisateur.

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

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.

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 de valeur 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);

Remarquez, c'est la manière la plus élégante de le faire.

Un des endroits que j'utilise est le code de socket. Par exemple, si vous avez défini un délai d'attente, 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 )

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 (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 l'éteindre.

Si vous utilisez une fonction de gestion d'erreur 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
}

Aujourd’hui, j’ai rencontré un problème qui donnait un bon exemple de l’opportunité 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 qui lui est propre, 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 attend 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 ici est de refactoriser ladite classe, au lieu d’utiliser un nom d’utilisateur et un mot de passe en tant que 2 paramètres, par exemple en utilisant un seul paramètre tableau contenant ces 2 valeurs (la trace écrira Array pour le paramètre dans ces cas). Il existe également d’autres moyens de s’attaquer à ce problème, mais c’est un tout autre problème.

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

La leçon que j'ai apprise dès que j'ai remarqué cette sortie de trace: il est parfois utile de supprimer un message d'erreur pour le moment, ce qui est une mesure utile pour éviter un préjudice supplémentaire.

À mon avis, je ne pensais pas que ce soit un cas de mauvais design de classe. L’erreur elle-même a été déclenchée par une exception PDOException (problème d’horodatage déplaçant MySQL 5.6 à 5.7) qui vient tout simplement d’être sauvegardée par PHP 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 de rapide jusqu'à ce que le problème soit correctement résolu.

Je l'utilise pour essayer de charger un fichier HTML à traiter en tant qu'objet DOMDocument. S'il y a des problèmes dans le code HTML ... et que le site Web ne possède pas au moins un ... DOMDocument- > loadHTMLFile () renvoie une erreur si vous ne le supprimez pas avec @. C’est le seul moyen (c’est peut-être meilleur) que j’ai réussi à créer des scrapers HTML en PHP.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top