handling - try catch php mysql
¿Puedo probar/atrapar una advertencia? (10)
Necesito detectar algunas advertencias que se emiten desde algunas funciones nativas de php y luego manejarlas.
Específicamente:
array dns_get_record ( string $hostname [, int $type= DNS_ANY [, array &$authns [, array &$addtl ]]] )
Se emite una advertencia cuando la consulta de DNS falla.
try
/ catch
no funciona porque una advertencia no es una excepción.
Ahora tengo 2 opciones:
set_error_handler
parece una exageración porque tengo que usarlo para filtrar cada advertencia en la página (¿es esto cierto?);Ajuste el informe / visualización de errores para que estas advertencias no se muestren en la pantalla, luego verifique el valor de retorno; si es
false
, no se encuentran registros para el nombre de host.
¿Cuál es la mejor práctica aquí?
La combinación de estas líneas de código alrededor de una llamada file_get_contents()
a una url externa me ayudó a manejar advertencias como " no se pudo abrir la transmisión: la conexión expiró " mucho mejor:
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();
Esta solución también funciona dentro del contexto del objeto. Podrías usarlo en una función:
public function myContentGetter($sUrl)
{
... code above ...
return $iResult;
}
La solución que realmente funciona resultó ser configurar un sencillo controlador de errores con el parámetro E_WARNING
, como:
set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();
function warning_handler($errno, $errstr) {
// do something
}
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 existe el registro.
Probablemente debería intentar deshacerse de la advertencia por completo, pero si eso no es posible, puede preparar la llamada con @ (es decir, @dns_get_record (...)) y luego usar cualquier información que pueda obtener para averiguar si ocurrió la advertencia. o no.
Quería probar / capturar una advertencia, pero al mismo tiempo mantener la advertencia / registro de errores habituales (por ejemplo, en /var/log/apache2/error.log
); Para lo cual el manejador tiene que devolver false
. Sin embargo, dado que la instrucción "lanzar nuevo ..." básicamente interrumpe la ejecución, uno tiene que hacer el truco de "envolver en función", que también se analiza en:
¿Hay una forma estática para lanzar excepciones en PHP
O, en breve:
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();
// ...
}
EDITAR: después de una inspección más cercana, resulta que no funciona: la " return false && throwErrorException ...
", básicamente, no lanzará la excepción, y simplemente iniciará sesión en el registro de errores; eliminar la parte " false &&
", como en " return throwErrorException ...
", hará que el lanzamiento de la excepción funcione, pero luego no se registrará en el error_log ... Todavía mantendré esto publicado, ya que no lo tengo. He visto este comportamiento documentado en otra parte.
Si dns_get_record()
falla, debería devolver FALSE
, por lo que puede suprimir la advertencia con @
y luego verificar el valor de retorno.
Solo recomendaría usar @ para suprimir las advertencias cuando se trata de una operación directa (por ejemplo, $ prop = @ ($ high / ($ width - $ depth)); para omitir las advertencias de división por cero). Sin embargo, en la mayoría de los casos es mejor manejar.
intente verificar si devuelve algún valor booleano, entonces simplemente puede ponerlo como una condición. Encontré esto con el oci_execute (...) que estaba devolviendo alguna violación con mis claves únicas.
ex.
oci_parse($res, "[oracle pl/sql]");
if(oci_execute){
...do something
}
Establecer y restaurar el controlador de errores
Una posibilidad es configurar su propio controlador de errores antes de la llamada y restaurar posteriormente el controlador de errores anterior con restore_error_handler()
.
set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();
Podría desarrollar esta idea y escribir un controlador de errores reutilizable que registre los errores por usted.
set_error_handler([$logger, ''onSilencedError'']);
dns_get_record();
restore_error_handler();
Convertir errores en excepciones.
Puede usar 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 tener en cuenta al usar su propio controlador de errores es que error_reporting
configuración error_reporting
y pasará todos los errores (avisos, advertencias, etc.) a su 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 utilizando ... = error_reporting()
dentro del controlador de errores.
Suprimiendo la advertencia
Otra posibilidad es suprimir la llamada con el operador @ y verificar el valor de retorno de dns_get_record()
posteriormente. Pero desaconsejaría esto, ya que los errores / advertencias se activan para ser manejados, no para ser suprimidos.
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 el soporte mysql no estaba cargado en PHP y arrojó un error fatal silencioso. Será seguro para aquellas cosas que forman parte del núcleo de PHP pero, por favor, úselo con cuidado.
bob@mypc:~$ php -a
Interactive shell
php > echo @something(); // this will just silently die...
No hay más salida - buena suerte depurando esto!
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:~$
Esta vez podemos ver por qué falló.