web-dev-qa-db-fra.com

Arrêtez l'exécution du script sur notification/avertissement

Est-il possible que PHP arrête l'exécution lors d'une notification/avertissement, globalement?

Nous exécutons un serveur de développement avec beaucoup de sites, mais voulons forcer nos développeurs à résoudre ces avertissements/notifications (ou au moins à demander de l'aide), au lieu de les ignorer et de passer à autre chose.

35
Michael

Oui c'est possible. Cette question concerne le problème plus général de la gestion des erreurs en PHP. Vous devez définir et enregistrer un gestionnaire d'erreurs personnalisé à l'aide de set_error_handlerdocs pour personnaliser le traitement des erreurs PHP.

IMHO il est préférable de lancer une exception sur toute erreur PHP et d'utiliser des blocs try/catch pour contrôler le déroulement du programme, mais les avis divergent sur ce point.

Pour atteindre l'objectif déclaré du PO, vous pouvez effectuer les tâches suivantes:

function errHandle($errNo, $errStr, $errFile, $errLine) {
    $msg = "$errStr in $errFile on line $errLine";
    if ($errNo == E_NOTICE || $errNo == E_WARNING) {
        throw new ErrorException($msg, $errNo);
    } else {
        echo $msg;
    }
}

set_error_handler('errHandle');

Le code ci-dessus lancera une ErrorException chaque fois qu'un E_NOTICE ou E_WARNING est généré, mettant ainsi fin à la sortie du script (si l'exception n'est pas interceptée). Il est préférable de combiner les exceptions sur les erreurs PHP à une stratégie de traitement des exceptions parallèles ( set_exception_handler ) pour terminer en douceur dans les environnements de production.

Notez que l'exemple ci-dessus ne respectera pas l'opérateur de suppression d'erreur @. Si cela est important pour vous, ajoutez simplement une vérification à l'aide de la fonction error_reporting(), comme illustré ici:

function errHandle($errNo, $errStr, $errFile, $errLine) {
    if (error_reporting() == 0) {
        // @ suppression used, don't worry about it
        return;
    }
    // handle error here
}
48
rdlowrey

À partir de PHP 5.3.0:

set_error_handler(
    function(int $nSeverity, string $strMessage, string $strFilePath, int $nLineNumber){
        if(error_reporting()!==0) // Not error suppression operator @
            throw new \ErrorException($strMessage, /*nExceptionCode*/ 0, $nSeverity, $strFilePath, $nLineNumber);
    },
    /*E_ALL*/ -1
);
6

Vous pouvez configurer ceci globalement dans votre fichier php.iniDocs .

Pour cela, vous spécifiez un fichier inclus par tous les processus PHP avec la directive auto_prepend_fileDocs :

auto_prepend_file "/full/path/to/a/prepend-file.php"

En faisant cela dans votre fichier global php.ini, vous vous assurerez que le code contenu dans le fichier prepend sera toujours exécuté. Vous pouvez ensuite l’utiliser pour enregistrer un gestionnaire d’erreurs global qui transformera toutes les erreurs en exceptions).Docs :

<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");

Ce petit script transformera toutes les erreurs/avertissements/remarques, etc. en un ErrorException .

Combinez-le avec la directive error_reporting iniDocs }, les valeurs sont décrites dans votre fichier php.ini.

Lancer une exception est une chose très stricte. Vos programmeurs seront obligés de gérer les avertissements et les erreurs sinon le code ne fonctionnera pas.

C’est probablement trop pour vos programmeurs et non socialement acceptable au sein de votre entreprise. Au lieu de cela, vous pouvez également enregistrer toutes les erreurs et les ajouter à la fin de la sortie (ou plus haut pour la rendre plus visible) en utilisant la mise en mémoire tampon de la sortie.

Une autre solution consiste à consigner les erreurs et les avertissements dans le fichier journal, puis à surveiller ce fichier avec un autre processus et à regrouper les informations. Vous pouvez créer un tableau de bord affichant le nombre d'avertissements par application et le rendre visible au bureau afin que tout le monde puisse voir à quel point une équipe se comporte ou s'amuse comme ça.

Ce que j’essaie de dire, c’est: En plus du problème technique, c’est un problème de société avec lequel vous devez faire preuve de créativité et parler réellement du problème à vos développeurs. Vous devez expliquer pourquoi il est important de corriger les avertissements et les erreurs et comment leur codage et leurs compétences en tireront parti.

6
hakre

Si vous êtes dans un environnement de développement, vous pouvez envisager d’installer le module Xdebug et de définir xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE quelque part dans vos fichiers ini PHP. Le développeur peut réinitialiser xdebug.halt_level, mais nous avons le même problème avec la réponse basée sur set_error_handler, car nous pouvons restaurer le gestionnaire à sa valeur d'origine. 

3
user2066805

Les autres solutions implémentent un gestionnaire d'erreurs personnalisé qui remplace le mécanisme de consignation des erreurs par défaut. Cela signifie que lorsque nous définissons un gestionnaire d’erreurs personnalisé, la notification/avertissement n’est plus imprimée de la manière par défaut. Nous changeons donc plus que simplement "arrêter l’exécution du script lors de la notification/avertissement".

Cependant, il me fallait un moyen de continuer à imprimer le message - dans mon cas, dans PHP CLI -, car la sortie est ensuite analysée par un autre programme. Donc, je ne voulais pas imprimer le message de d'une certaine manière mais exactement de la même manière que le fait habituellement PHP. Je juste je voulais arrêter le processus CLI PHP avec un code de sortie de != 0 juste après qu'un avis/avertissement a été imprimé, et je ne change rien d'autre .

Malheureusement, il ne semble pas y avoir de moyen par défaut de quitter le script sans modifier toute la gestion des erreurs . Il me fallait donc réimplémenter le gestionnaire d'erreurs par défaut (implémenté en C) en PHP.

Pour cela, j'ai examiné le mécanisme d'impression d'erreur par défaut dans le code source de PHP et porté les éléments pertinents de C vers PHP pour obtenir le gestionnaire d'erreurs suivant, que je souhaite partager avec vous au cas où vous auriez besoin de quelque chose de similaire:

set_error_handler(
    function($errNo, $errStr, $errFile, $errLine) {
        $error_type_str = 'Error';
        // Source of the switch logic: default error handler in PHP's main.c
        switch ($errNo) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                $error_type_str = "Fatal error";
                break;
            case E_RECOVERABLE_ERROR:
                $error_type_str = "Recoverable fatal error";
                break;
            case E_WARNING:
            case E_CORE_WARNING:
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
                $error_type_str = "Warning";
                break;
            case E_PARSE:
                $error_type_str = "Parse error";
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                $error_type_str = "Notice";
                break;
            case E_STRICT:
                $error_type_str = "Strict Standards";
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                $error_type_str = "Deprecated";
                break;
            default:
                $error_type_str = "Unknown error";
                break;
        }
        fwrite(STDERR, "PHP $error_type_str:  $errStr in $errFile on line $errLine\n");
        exit(1);
    },
    E_ALL
);
0
leemes