Question

Je dois attraper quelques avertissements être projetés de certaines fonctions natives de PHP et de les gérer.

Plus précisément:

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

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

try / catch ne fonctionne pas parce qu'un avertissement ne fait pas exception.

J'ai maintenant 2 options:

  1. set_error_handler semble exagéré parce que je dois l'utiliser pour filtrer tous les avertissement dans la page (est-ce vrai?);

  2. Ajuster les rapports / affichage d'erreur si ces avertissements ne sont pas résonnaient à l'écran, puis vérifiez la valeur de retour; si elle est false, aucun enregistrement est trouvé pour le nom d'hôte.

Quelle est la meilleure pratique ici?

Était-ce utile?

La solution

Définir et restaurer gestionnaire d'erreurs

Une possibilité est de définir votre propre gestionnaire d'erreurs avant l'appel et restaurer le gestionnaire d'erreurs précédente plus tard avec restore_error_handler().

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

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

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

Mise erreurs en exceptions

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

set_error_handler(function($errno, $errstr, $errfile, $errline, $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) {
    // ...
}

La chose importante à noter lorsque vous utilisez votre propre gestionnaire d'erreur est qu'il contournera le réglage de error_reporting et de transmettre toutes les erreurs (avis, avertissements, etc.) à votre gestionnaire d'erreurs. Vous pouvez définir un second argument sur set_error_handler() pour définir quels types d'erreur que vous souhaitez recevoir, ou accéder au réglage actuel à l'aide ... = error_reporting() dans le gestionnaire d'erreur.

Suppression l'avertissement

Une autre possibilité est de supprimer l'appel avec l'opérateur @ et vérifier la valeur de retour de dns_get_record() après. Mais je vous conseille contre cette comme des erreurs / avertissements sont déclenchés à manipuler, ne doit pas être supprimé.

Autres conseils

La solution qui fonctionne vraiment avéré être mise gestionnaire d'erreur simple paramètre E_WARNING, comme suit:

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

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

Attention avec l'opérateur @ - alors qu'il supprime les avertissements, il supprime également des erreurs fatales. J'ai passé beaucoup de temps le débogage d'un problème dans un système où quelqu'un avait écrit @mysql_query( '...' ) et le problème est que le support MySQL n'a pas été chargé dans PHP et il a jeté une erreur fatale silencieuse. Il sera sans danger pour ces choses qui font partie du noyau de PHP, mais s'il vous plaît utiliser avec soin.

bob@mypc:~$ php -a
Interactive shell

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

Pas de sortie plus - bonne chance débogage ce

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-ci, nous pouvons voir pourquoi il a échoué.

Je voulais essayer / attraper un avertissement, mais en même temps de conserver la consignation de l'avertissement / erreur habituelle (par exemple dans /var/log/apache2/error.log); pour lequel le gestionnaire doit retourner false. Cependant, depuis le « throw new ... » déclaration interrompt essentiellement l'exécution, on doit alors faire l'affaire « envelopper dans la fonction », a également discuté dans:

Y at-il une manière statique jeter 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 un examen plus approfondi, il se trouve qu'il ne fonctionne pas: le « return false && throwErrorException ... » sera, essentiellement, pas jeter l'exception, et connectez-vous dans le journal des erreurs; enlever la partie « false && », comme dans « return throwErrorException ... », fera l'exception de lancer le travail, mais alors pas connecter le error_log ... Je serais toujours garder ce affiché, mais, comme je l'ai pas vu ce comportement documenté ailleurs.

Vous devriez probablement essayer de se débarrasser de l'avertissement complètement, mais si cela est impossible, vous pouvez préfixer l'appel avec @ (c.-à-@dns_get_record (...)) et ensuite utiliser toute information que vous pouvez obtenir à savoir si l'avertissement est passé ou non.

Normaly vous ne devez jamais utiliser @ sauf si cela est la seule solution. Dans ce cas précis, la fonction doit être dns_check_record utiliser d'abord savoir si l'enregistrement existe.

La combinaison de ces lignes de code autour d'un appel file_get_contents() à une URL externe m'a aidée à résoudre les avertissements comme "failed to open stream : Délai de connexion dépassé " 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 dans le contexte de l'objet, aussi. Vous pouvez l'utiliser dans une fonction:

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

Si dns_get_record() échoue, il doit retourner FALSE, de sorte que vous pouvez supprimer l'avertissement avec @ puis vérifier la valeur de retour.

essayez de vérifier si elle retourne une valeur booléenne, vous pouvez simplement le mettre comme condition. Je rencontrais cela avec la oci_execute (...) qui retournait une violation avec mes clés uniques.

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

FolderStructure

index.php //Script File
logs //Folder for log Every warning and Errors
CustomException.php //Custom exception File

CustomException.php

/**
* Custom error handler
*/
function handleError($code, $description, $file = null, $line = null, $context = null) {
    $displayErrors = ini_get("display_errors");;
    $displayErrors = strtolower($displayErrors);
    if (error_reporting() === 0 || $displayErrors === "on") {
        return false;
    }
    list($error, $log) = mapErrorCode($code);
    $data = array(
        'timestamp' => date("Y-m-d H:i:s:u", time()),
        'level' => $log,
        'code' => $code,
        'type' => $error,
        'description' => $description,
        'file' => $file,
        'line' => $line,
        'context' => $context,
        'path' => $file,
        'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
    );
    $data = array_map('htmlentities',$data);
    return fileLog(json_encode($data));
}

/**
* This method is used to write data in file
* @param mixed $logData
* @param string $fileName
* @return boolean
*/
function fileLog($logData, $fileName = ERROR_LOG_FILE) {
    $fh = fopen($fileName, 'a+');
    if (is_array($logData)) {
        $logData = print_r($logData, 1);
    }
    $status = fwrite($fh, $logData . "\n");
    fclose($fh);
//    $file = file_get_contents($filename);
//    $content = '[' . $file .']';
//    file_put_contents($content); 
    return ($status) ? true : false;
}

/**
* Map an error code into an Error word, and log location.
*
* @param int $code Error code to map
* @return array Array of error word, and log location.
*/
function mapErrorCode($code) {
    $error = $log = null;
    switch ($code) {
        case E_PARSE:
        case E_ERROR:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
            $error = 'Fatal Error';
            $log = LOG_ERR;
            break;
        case E_WARNING:
        case E_USER_WARNING:
        case E_COMPILE_WARNING:
        case E_RECOVERABLE_ERROR:
            $error = 'Warning';
            $log = LOG_WARNING;
            break;
        case E_NOTICE:
        case E_USER_NOTICE:
            $error = 'Notice';
            $log = LOG_NOTICE;
            break;
        case E_STRICT:
            $error = 'Strict';
            $log = LOG_NOTICE;
            break;
        case E_DEPRECATED:
        case E_USER_DEPRECATED:
            $error = 'Deprecated';
            $log = LOG_NOTICE;
            break;
        default :
            break;
    }
    return array($error, $log);
}
//calling custom error handler
set_error_handler("handleError");

il suffit d'inclure ci-dessus fichier dans votre fichier de script comme celui-ci

index.php

error_reporting(E_ALL);
ini_set('display_errors', 'off');
define('ERROR_LOG_FILE', 'logs/app_errors.log');

include_once 'CustomException.php';
echo $a; // here undefined variable warning will be logged into logs/app_errors.log

Je ne recommanderais en utilisant @ pour supprimer les avertissements quand il est une opération avant droit (par exemple $ prop = @ ($ haut / (largeur $ - profondeur de $)); sauter division par zéro avertissements). Cependant, il est préférable de traiter dans la plupart des cas.

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