2009-08-06 21 views
266

Necesito detectar algunas advertencias lanzadas desde algunas funciones nativas de php y luego manejarlas.¿Puedo probar/detectar una advertencia?

Específicamente:

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

Se lanza una advertencia cuando la consulta DNS falla.

try/catch no funciona porque una advertencia no es una excepción.

ahora tengo 2 opciones:

  1. set_error_handler parece un exceso porque tengo que usarlo para filtrar cada advertencia en la página (? ¿Es cierto);

  2. Ajusta el informe/visualización de errores para que estas advertencias no se repitan en la pantalla, luego verifica el valor de retorno; si es false, no se encuentran registros para nombre de host.

¿Cuál es la mejor práctica aquí?

+1

http://stackoverflow.com/questions/136899/suppress-error-with-operator-in-php es una buena discusión sobre este tipo de cosas. – Mez

+0

hubo una respuesta debajo que se eliminó? ya sea por el propietario o por alguien? – user121196

+0

vea también: http://stackoverflow.com/questions/1087365 – dreftymac

Respuesta

293

Set y restaurar el gestor de errores

Una posibilidad es establecer su propio gestor de errores antes de la llamada y restaurar la gestión de errores previa después con restore_error_handler().

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

Puede basarse en esta idea y escribir un controlador de errores reutilizable que registra los errores por usted.

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

errores que se convierten en excepciones

Puede utilizar set_error_handler() y la clase ErrorException para convertir todos los errores de PHP en excepciones.

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

Lo importante a cuenta al utilizar su propio controlador de errores es que va a pasar por alto la configuración error_reporting y pasar todos los errores (avisos, advertencias, etc.) al controlador de errores. Puede establecer un segundo argumento en set_error_handler() para definir qué tipos de error desea recibir, o acceder a la configuración actual usando ... = error_reporting() dentro del controlador de errores.

Suprimir la advertencia

Otra posibilidad es la de suprimir la llamada con el operador @ y comprobar el valor de retorno de dns_get_record() después. Pero desaconsejaré esto ya que los errores/advertencias se activan para no ser suprimidos.

+3

¿es aconsejable configurar mi propio manejador de errores justo antes de la llamada a la función, luego restore_error_handler cuando se realiza la comprobación de errores? – user121196

+2

esto será seguro para subprocesos si hay muchas solicitudes concurrentes, y cada solicitud hace 1.set_error_handler(). 2.doit 3.restore_error_handler? – user121196

+1

1. si esto es una buena práctica? Realmente no lo sé pero si los tipos de Zend usan este método, realmente no puede ser tan malo. 2. cada solicitud es autónoma, por lo que no habrá ningún problema. –

4

Probablemente deberías tratar de deshacerte de la advertencia por completo, pero si eso no es posible, puedes anteponer la llamada con @ (es decir, @dns_get_record (...)) y luego usar cualquier información que puedas obtener para descubrir si la advertencia sucedió o no.

2

Si falla dns_get_record(), debe devolver FALSE, por lo que puede suprimir la advertencia con @ y luego verificar el valor de retorno.

3

Normalmente, nunca debe usar @ a menos que esta sea la única solución. En ese caso específico, la función dns_check_record debe usarse primero para saber si el registro existe.

24

Tenga cuidado con el operador @ - mientras suprime las advertencias, también suprime los errores fatales. Pasé mucho tiempo depurando un problema en un sistema donde alguien había escrito @mysql_query('...') y el problema era que la compatibilidad con mysql no se cargaba en PHP y arrojaba un error fatal silencioso. Será seguro para aquellas cosas que son parte del núcleo de PHP pero por favor úselo con cuidado.

[email protected]:~$ php -a 
Interactive shell 

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

Sin salida adicional - ¡buena suerte depurando esto!

[email protected]:~$ 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 
[email protected]:~$ 

Esta vez podemos ver por qué falló.

107

La solución que realmente funciona resultó ser la creación gestor de errores sencillo con E_WARNING parámetro, así:

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

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

solución muy elegante. ¡ACTUALIZADO! :) –

+3

también se puede usar 'callable' anónimo aquí en lugar de cadena con declaración de función –

+0

Gracias, pero ¿cómo puedo eliminar el manejador de errores después del bloque crítico? –

5

quería probar/coger una advertencia, pero al mismo tiempo mantener la advertencia habitual/registro de errores (por ejemplo, en /var/log/apache2/error.log); para lo cual el controlador debe devolver false. Sin embargo, puesto que el "tiro de nuevo ..." declaración básicamente interrumpe la ejecución, a continuación, uno tiene que hacer el truco "envolver en la función", también se discutió en:

Is there a static way to throw exception in php

O, en pocas palabras:

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: después de una inspección más cercana, resulta que no funciona: el "return false && throwErrorException ..." será, básicamente, no emitir la excepción, y sólo tiene que entrar en el registro de errores; eliminar la parte "false &&", como en "return throwErrorException ...", hará que la excepción funcione, pero luego no iniciará sesión en el error_log ... Aún así lo mantendré informado, ya que no he visto documentado este comportamiento en otra parte.

-2

Recomendaría usar @ para suprimir advertencias cuando se trata de una operación directa (por ejemplo, $ prop = @ ($ high/($ width - $ depth)); omita la división mediante cero advertencias). Sin embargo, en la mayoría de los casos, es mejor manejarlo.

+1

Esta es una vez que definitivamente no desea usar @; tiene control sobre la operación y puede verificar si es una división por cero o no antes de hacerlo. – Eborbob

0

intente comprobar si devuelve algún valor booleano, entonces simplemente puede ponerlo como una condición. Encontré esto con el oci_execute (...) que devolvía alguna violación con mis claves únicas.

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