Lección 49 de 75 10 min de lectura

Tipos de Errores en PHP

PHP tiene un sistema de errores que clasifica los problemas según su gravedad. Entender estos tipos te ayudará a depurar tu código y a configurar correctamente el reporte de errores en desarrollo y producción.

Niveles de error en PHP

PHP clasifica los errores en diferentes niveles según su impacto en la ejecución:

Constante Descripción ¿Detiene ejecución?
E_ERROR Error fatal. Problema grave irrecuperable.
E_WARNING Advertencia. Algo salió mal pero puede continuar. No
E_NOTICE Aviso. Posible problema, código sigue ejecutándose. No
E_PARSE Error de sintaxis. El código no puede interpretarse.
E_DEPRECATED Funcionalidad obsoleta que será eliminada. No
E_STRICT Sugerencias para mejorar compatibilidad. No

Errores fatales (E_ERROR)

Detienen la ejecución inmediatamente. No hay forma de continuar después de un error fatal:

PHP
<?php

declare(strict_types=1);

// Llamar a una función que no existe
funcionQueNoExiste();
// Fatal error: Uncaught Error: Call to undefined function

// Instanciar una clase que no existe
$objeto = new ClaseInexistente();
// Fatal error: Uncaught Error: Class "ClaseInexistente" not found

// Agotar la memoria
ini_set('memory_limit', '1M');
$array = range(1, 10000000);
// Fatal error: Allowed memory size exhausted

Advertencias (E_WARNING)

Indican un problema pero permiten que el script continúe. Es importante corregirlas porque pueden causar comportamientos inesperados:

PHP
<?php

declare(strict_types=1);

// Incluir un archivo que no existe
include 'archivo_inexistente.php';
// Warning: include(archivo_inexistente.php): Failed to open stream
// El script continúa ejecutándose

// División por cero (PHP 8+: ahora es DivisionByZeroError)
// En versiones anteriores era warning
$resultado = 10 / 0;

// Argumento incorrecto a una función
$array = 'no soy un array';
$longitud = count($array);
// Warning: count(): Parameter must be an array or Countable

echo 'Este código sí se ejecuta después del warning';

Avisos (E_NOTICE)

Son los errores menos graves pero no deben ignorarse. Suelen indicar malas prácticas o posibles bugs:

PHP
<?php

declare(strict_types=1);

// Acceder a variable no definida (PHP 8+: ahora es Warning)
echo $variableNoDefinida;
// Warning: Undefined variable $variableNoDefinida

// Acceder a índice de array inexistente (PHP 8+: ahora es Warning)
$array = ['a' => 1, 'b' => 2];
echo $array['c'];
// Warning: Undefined array key "c"

// Forma correcta: verificar antes de acceder
if (isset($array['c'])) {
    echo $array['c'];
}

// O usar operador null coalescence
echo $array['c'] ?? 'valor por defecto';
PHP 8 es más estricto

Muchos errores que antes eran E_NOTICE ahora son E_WARNING en PHP 8. Algunos warnings se convirtieron en Error o TypeError.

Errores de sintaxis (E_PARSE)

Ocurren cuando el código tiene errores de sintaxis. PHP no puede ni siquiera empezar a ejecutar el script:

PHP
<?php

// Falta punto y coma
$nombre = 'Ana'
echo $nombre;
// Parse error: syntax error, unexpected token "echo"

// Paréntesis sin cerrar
if ($edad > 18 {
    echo 'Mayor de edad';
}
// Parse error: syntax error, unexpected token "{"

// Comillas sin cerrar
$mensaje = 'Hola mundo;
// Parse error: syntax error, unexpected end of file

Configurar el reporte de errores

PHP permite configurar qué errores se muestran y cómo. Esto es crucial para diferenciar entre desarrollo y producción:

PHP
<?php

declare(strict_types=1);

// Mostrar TODOS los errores (recomendado en desarrollo)
error_reporting(E_ALL);
ini_set('display_errors', '1');

// Mostrar solo errores y warnings (sin notices)
error_reporting(E_ERROR | E_WARNING);

// Mostrar todos excepto notices
error_reporting(E_ALL & ~E_NOTICE);

// Mostrar todos excepto notices y deprecated
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);

// No mostrar ningún error (NUNCA en desarrollo)
error_reporting(0);

// Verificar el nivel actual
$nivel = error_reporting();
echo "Nivel actual: $nivel";

Configuración recomendada

PHP
<?php

declare(strict_types=1);

// config.php - Configuración según el entorno

$entorno = getenv('APP_ENV') ?: 'development';

if ($entorno === 'development') {
    // DESARROLLO: ver todos los errores
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    ini_set('display_startup_errors', '1');
} else {
    // PRODUCCIÓN: ocultar errores, solo registrar en log
    error_reporting(E_ALL);
    ini_set('display_errors', '0');
    ini_set('log_errors', '1');
    ini_set('error_log', '/var/log/php/errors.log');
}

El operador de supresión @

El operador @ suprime los errores de una expresión. Evita usarlo porque oculta problemas reales:

PHP
<?php

declare(strict_types=1);

// MAL: suprimir errores con @
$contenido = @file_get_contents('archivo.txt');

// BIEN: manejar el error correctamente
$archivo = 'archivo.txt';
if (file_exists($archivo) && is_readable($archivo)) {
    $contenido = file_get_contents($archivo);
} else {
    $contenido = null;
    // Manejar el caso de archivo no disponible
}

// MEJOR: usar excepciones (lo veremos en la siguiente lección)
try {
    $contenido = file_get_contents($archivo);
    if ($contenido === false) {
        throw new RuntimeException("No se pudo leer: $archivo");
    }
} catch (RuntimeException $e) {
    // Manejar el error
    $contenido = null;
}

Errores vs Excepciones en PHP 8

PHP 8 convirtió muchos errores fatales en excepciones que pueden capturarse. Esto da más control sobre el manejo de errores:

PHP
<?php

declare(strict_types=1);

// TypeError: tipo de argumento incorrecto
function saludar(string $nombre): void
{
    echo "Hola, $nombre";
}

try {
    saludar(123); // Pasamos int en lugar de string
} catch (TypeError $e) {
    echo 'Error de tipo: ' . $e->getMessage();
}

// ArgumentCountError: número incorrecto de argumentos
function sumar(int $a, int $b): int
{
    return $a + $b;
}

try {
    sumar(1); // Falta un argumento
} catch (ArgumentCountError $e) {
    echo 'Faltan argumentos: ' . $e->getMessage();
}

// DivisionByZeroError
try {
    $resultado = 10 % 0; // Módulo por cero
} catch (DivisionByZeroError $e) {
    echo 'División por cero: ' . $e->getMessage();
}

Jerarquía de Throwable

En PHP 7+, todos los errores y excepciones implementan la interfaz Throwable:

TEXT
Throwable (interfaz)
├── Error (errores internos de PHP)
│   ├── TypeError
│   ├── ArgumentCountError
│   ├── ArithmeticError
│   │   └── DivisionByZeroError
│   ├── ParseError
│   └── AssertionError
│
└── Exception (excepciones de usuario)
    ├── RuntimeException
    ├── InvalidArgumentException
    ├── LogicException
    └── ... (muchas más)
PHP
<?php

declare(strict_types=1);

// Capturar cualquier error o excepción
try {
    // Código que puede fallar
    $resultado = operacionRiesgosa();
} catch (Throwable $t) {
    // Captura tanto Error como Exception
    echo 'Algo falló: ' . $t->getMessage();
}

// Capturar por separado
try {
    $resultado = operacionRiesgosa();
} catch (TypeError $e) {
    echo 'Error de tipo';
} catch (Exception $e) {
    echo 'Excepción: ' . $e->getMessage();
} catch (Error $e) {
    echo 'Error interno: ' . $e->getMessage();
}

Ejercicios

Ejercicio 1: Configurar entorno

Crea un archivo config.php que configure el reporte de errores según una constante DEBUG. Si es true, mostrar todos los errores. Si es false, solo registrarlos en un archivo de log.

Ver solución
<?php

declare(strict_types=1);

// config.php
define('DEBUG', true); // Cambiar a false en producción

error_reporting(E_ALL);

if (DEBUG) {
    // DESARROLLO: mostrar todos los errores
    ini_set('display_errors', '1');
    ini_set('display_startup_errors', '1');
} else {
    // PRODUCCIÓN: ocultar errores, registrar en log
    ini_set('display_errors', '0');
    ini_set('log_errors', '1');
    ini_set('error_log', __DIR__ . '/logs/errores.log');
}

Ejercicio 2: Identificar tipos de error

Escribe código que genere intencionalmente: un Warning (incluir archivo inexistente con include), un TypeError (pasar tipo incorrecto a función tipada), y un Error por variable indefinida. Captura cada uno y muestra un mensaje descriptivo.

Ver solución
<?php

declare(strict_types=1);

// 1. Warning: incluir archivo inexistente
echo "--- Warning ---\n";
$resultado = @include 'archivo_que_no_existe.php';
if ($resultado === false) {
    echo "Warning capturado: archivo no encontrado\n";
}

// 2. TypeError: tipo incorrecto
echo "\n--- TypeError ---\n";
function saludar(string $nombre): string
{
    return "Hola, $nombre";
}

try {
    saludar(123);
} catch (TypeError $e) {
    echo "TypeError capturado: " . $e->getMessage() . "\n";
}

// 3. Warning por variable indefinida
echo "\n--- Variable indefinida ---\n";
$valor = $variableNoDefinida ?? 'valor por defecto';
echo "Manejado con ??: $valor\n";

Ejercicio 3: Reemplazar @ por manejo correcto

Dado este código que usa el operador de supresión: $json = @json_decode($input);, reescríbelo para manejar el error correctamente usando json_last_error() y lanzando una excepción si el JSON es inválido.

Ver solución
<?php

declare(strict_types=1);

function decodificarJson(string $input): mixed
{
    $datos = json_decode($input, true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new InvalidArgumentException(
            'JSON inválido: ' . json_last_error_msg()
        );
    }

    return $datos;
}

// Prueba con JSON válido
try {
    $resultado = decodificarJson('{"nombre": "Ana", "edad": 25}');
    print_r($resultado);
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
}

// Prueba con JSON inválido
try {
    $resultado = decodificarJson('{"nombre": "Ana", edad: 25}');
} catch (InvalidArgumentException $e) {
    echo "Error: " . $e->getMessage();
    // Error: JSON inválido: Syntax error
}

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte.

Descubrir cursos premium