Curso de PHP
Gestión de errores en PHP: tipos, configuración y registro
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de PHP, hoy veremos la gestión de errores. En la lección anterior sobre excepciones vimos cómo manejar los problemas que tú detectas; ahora toca lo que hace PHP cuando algo falla.
¡Empecemos!
Errores y excepciones no son lo mismo
Es la confusión más frecuente del tema, así que empecemos por ahí.
- Una excepción es un objeto que tú lanzas y capturas. Forma parte del diseño de tu programa.
- Un error lo genera PHP cuando ocurre algo que no debería: una variable inexistente, un archivo que no se puede abrir, una función mal llamada.
En PHP moderno ambos comparten la interfaz Throwable, pero viven en ramas distintas de la jerarquía. Por eso, como vimos, catch (Exception $e) no captura un TypeError.
Los tipos de error
| Nivel | Qué significa | ¿Detiene el script? |
|---|---|---|
E_ERROR |
Error fatal | Sí |
E_WARNING |
Advertencia | No |
E_NOTICE |
Aviso menor | No |
E_DEPRECATED |
Función obsoleta | No |
E_PARSE |
Error de sintaxis | Sí |
Ejemplos de cada uno:
<?php
echo $noExiste; // Warning: variable indefinida
echo 10 / 0; // DivisionByZeroError: fatal
$archivo = fopen("x.txt", "r"); // Warning si no existe
funcionInexistente(); // Error fatal
Un detalle importante: una advertencia no detiene el script, y eso es peligroso. El programa sigue con datos incorrectos y el fallo real aparece más adelante, en otro sitio.
La configuración que lo cambia todo
Aquí está lo más importante de esta lección. PHP se configura de forma opuesta en desarrollo y en producción.
En desarrollo: quiero verlo todo
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
Quieres que cualquier aviso, por pequeño que sea, aparezca en pantalla. Un E_NOTICE ignorado hoy es un error en producción mañana.
En producción: no mostrar nada, registrarlo todo
<?php
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/ruta/a/logs/php-errores.log');
error_reporting(E_ALL);
Nunca muestres errores en un servidor público. Un mensaje de error revela rutas de archivos, nombres de tablas, versiones de software y a veces credenciales. Es información que un atacante agradece.
La combinación correcta es: el usuario ve un mensaje genérico, y el detalle completo queda en el log.
Estas mismas opciones se configuran en el archivo php.ini, que es lo recomendable en producción. Recuerda que puedes ver su ubicación con phpinfo(), como vimos en la lección de instalación.
Convertir errores en excepciones
Esta es una técnica muy útil: hacer que cualquier advertencia se comporte como una excepción, para poder capturarla:
<?php
set_error_handler(function (int $tipo, string $mensaje, string $archivo, int $linea) {
throw new ErrorException($mensaje, 0, $tipo, $archivo, $linea);
});
try {
$contenido = file_get_contents("archivo-inexistente.txt");
} catch (ErrorException $e) {
echo "No se pudo leer el archivo: " . $e->getMessage();
}
Sin esto, file_get_contents() emitiría una advertencia, devolvería false y el script seguiría con un valor inútil.
Capturar errores fatales
Los errores fatales no se pueden capturar con try/catch, pero sí registrar antes de que el script muera:
<?php
register_shutdown_function(function () {
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
error_log("Error fatal: {$error['message']} en {$error['file']}:{$error['line']}");
// Mostrar algo decente al usuario
http_response_code(500);
echo "Ocurrió un error. Nuestro equipo ya fue notificado.";
}
});
Es lo que evita que el visitante vea una pantalla en blanco o un volcado técnico.
Un manejador global de excepciones
Para las excepciones que nadie capturó:
<?php
set_exception_handler(function (Throwable $e) {
error_log(sprintf(
"[%s] %s en %s:%d\n%s",
get_class($e),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
));
http_response_code(500);
echo "Ocurrió un error inesperado.";
});
Con esto y el anterior, ningún error queda sin registrar y el usuario nunca ve detalles internos.
Registrar errores tú mismo
<?php
error_log("El pedido 45 no pudo procesarse");
Escribe en el log configurado. Para depurar durante el desarrollo:
<?php
error_log(print_r($datos, true)); // el true devuelve el texto en vez de imprimirlo
Un aviso: nunca uses var_dump() o echo para depurar en un servidor de producción. Además de exponer información, se queda ahí olvidado durante meses.
Silenciar errores: el operador @
PHP permite silenciar un error anteponiendo @:
<?php
$contenido = @file_get_contents("archivo.txt");
Evítalo. Esconde el problema sin resolverlo y hace que depurar sea un infierno. Si esperas que algo pueda fallar, compruébalo antes o captúralo con try/catch:
<?php
if (!file_exists("archivo.txt")) {
throw new RuntimeException("El archivo no existe");
}
$contenido = file_get_contents("archivo.txt");
Un ejemplo práctico
Un manejador de errores completo para una aplicación:
<?php
declare(strict_types=1);
class ManejadorDeErrores
{
public function __construct(
private bool $enDesarrollo,
private string $rutaLog,
) {}
public function registrar(): void
{
error_reporting(E_ALL);
ini_set('display_errors', $this->enDesarrollo ? '1' : '0');
ini_set('log_errors', '1');
ini_set('error_log', $this->rutaLog);
set_error_handler([$this, 'manejarError']);
set_exception_handler([$this, 'manejarExcepcion']);
}
public function manejarError(
int $tipo,
string $mensaje,
string $archivo,
int $linea
): bool {
throw new ErrorException($mensaje, 0, $tipo, $archivo, $linea);
}
public function manejarExcepcion(Throwable $e): void
{
error_log(sprintf(
"[%s] %s en %s:%d",
get_class($e),
$e->getMessage(),
$e->getFile(),
$e->getLine()
));
http_response_code(500);
if ($this->enDesarrollo) {
echo "<pre>{$e}</pre>";
} else {
echo "Ocurrió un error. Intenta nuevamente en unos minutos.";
}
}
}
// Al inicio de la aplicación:
(new ManejadorDeErrores(
enDesarrollo: true,
rutaLog: __DIR__ . '/logs/errores.log'
))->registrar();
Fíjate en __DIR__, la constante mágica que vimos en la lección de constantes: hace que la ruta funcione sin importar desde dónde se ejecute el script.
Buenas prácticas
- Muestra todos los errores en desarrollo. Un aviso ignorado es un error futuro.
- No muestres ninguno en producción. Regístralos.
- Revisa el log periódicamente. Un log que nadie lee no sirve de nada.
- Nunca uses
@. - Ten un manejador global, para que nada quede sin registrar.
- Al usuario, mensajes claros y genéricos. Al log, todo el detalle.
Errores comunes
- Dejar
display_errorsactivo en producción. Es un problema de seguridad real. - Silenciar con
@en lugar de resolver. - Capturar y no registrar. El error desaparece sin dejar rastro.
- Confundir errores con excepciones y esperar que
catch (Exception $e)los atrape. - Depurar con
var_dump()en el servidor.
Para cerrar
La gestión de errores se resume en una frase: en desarrollo quieres verlo todo, en producción quieres registrarlo todo y mostrar nada.
Configura eso desde el primer día del proyecto y te ahorrarás muchísimo tiempo cuando algo falle.
En la siguiente lección veremos cómo conectar PHP con una base de datos.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp