Aprendiendo PHP, parte 14: Errores

PHP como cualquier otro lenguaje de programación puede generar errores. Algo importante de repasar es que existen lenguajes de programación interpretados y compilados. Un lenguaje de programación compilado como Java, en donde el programador escribe su código y antes de probar cómo está quedando su aplicación un compilador le indicará si hay errores, y de haberlo se frenará todo y el compilador le indicará al programador el problema.

Pero PHP no funciona de la misma forma, PHP es un lenguaje de programación interpretado, esto significa que nosotros vamos a escribir el código y si tenemos algún error el programa igual se ejecutará, luego el intérprete, en nuestro caso Apache, encontrará el error y detendrá su ejecución dependiendo de la gravedad del error.

Ahora bien, los errores no sólo pueden darse por errores del programador, por ejemplo por escribir con la sintaxis de forma incorrecta; también pueden darse factores que son ajenos al programador, por ejemplo si nosotros escribimos el código correcto para conectarse con una base de datos y de pronto alguien apaga la base de datos, nuestra aplicación no podrá conectarse y PHP lanzará un error por pantalla.

De todas formas, y desde mi punto de vista, tener o no errores no nos hace un mejor o peor programador, pero tener la capacidad y voluntad para evitarlos o resolverlos sí.

 

Errores más comunes

Existen varios errores que pueden darse en nuestro programa por errores del código, a continuación se detallan los más comunes:

Parse error

Estos errores se dan por un error de sintaxis en el código, por ejemplo si tenemos algo como esto:

function saraza{

}

Esto devolverá por pantalla:

Parse error: syntax error, unexpected '{', expecting '(' in

Por ejemplo, en este caso creamos una función y nos olvidamos de ponerle los paréntesis, por tanto el compilador encontrará el error y se romperá el script. Esto significa que todo lo que esté por debajo el intérprete va a ignorarlo.

Notice

Los errores de tipo Notice, son los errores ‘menos graves’ por así decirlo, pero esto no significa que no haya que corregirlos. Por ejemplo imprimir una variable que no está definida:

<?php 
 echo $variable_que_no_existe;
?>

Esto imprime por pantalla:

Notice: Undefined variable: variable_que_no_existe in

Estos errores serán tenidos en cuenta por el intérprete, pero éste continuará con su ejecución, por ejemplo si tuviéramos algo como esto:

<?php 
 echo $variable_que_no_existe;
 $variable_que_existe = 15;
 echo $variable_que_existe;
?>

En este caso se imprimirá por pantalla:

Notice: Undefined variable: variable_que_no_existe in
15

Osea, el intérprete nos informó del error, pero continuó con su ejecución, de hecho declaramos una variable con el valor 15 y lo imprimimos por pantalla.

En realidad cuando intentamos imprimir una variable que no está definida, si bien el intérprete lo toma como error inmediatamente le pasa como valor null.

Muchas veces los errores de tipo Notice suelen ser deshabilitados para que el intérprete no los imprima por pantalla, pero esto no es correcto. Por ejemplo si tuviéramos algo como esto:

<?php 
 $variable_que_existe = 15;
 $resultado = $variable_que_no_existe + $variable_que_existe;
 echo $resultado;
?>

En este caso como $variable_que_no_existe no está definida, y cuando sumamos $variable_que_existe, que vale 15 con $variable_que_no_existe, el intérprete le asignará un valor 0:

Notice: Undefined variable: variable_que_no_existe in

Warning

Los errores de tipo warning son errores que, al igual que los de tipo Notice, no romperán nuestro script, sin embargo nos están advirtiendo de que es muy probable que en las siguientes líneas algo no funcione correctamente debido al error que se está generando en la actual. Por ejemplo, si quisiéramos recuperar el contenido de un archivo que no existe:

<?php 
 $contenido = file_get_contents('archivo_que_no_existe.txt');
?>

Nos devolverá por pantalla:

Warning: file_get_contents(archivo_que_no_existe.txt): failed to open stream: No such file or directory in

Esto puede perjudicar nuestra aplicación más adelante, si por ejemplo luego intentamos imprimir el contenido del archivo (que no existe):

<?php 
 $contenido = file_get_contents('archivo_que_no_existe.txt');
 echo 'El contenido del archivo es: ' . $contenido;
?>

Esto nos devolverá:

Warning: file_get_contents(archivo_que_no_existe.txt): failed to open stream: No such file or directory in
El contenido del archivo es:

Como se ve en el ejemplo, después del Warning intenta mostrar el contenido del archivo, pero como el archivo no existe entonces imprime una cadena vacía después de ‘El contenido del archivo es:’

Fatal error

Los tipos de errores Fatal error romperán nuestro script a partir de la línea donde se producen, ya que el compilador no sabrá cómo continuar con la ejecución e ignorará las líneas que siguen:

<?php 
 $resultado = sumar(10, 5);
?>

Esto devuelve:

Fatal error: Call to undefined function sumar() in

En este caso estamos llamando a una función que nunca ha sido definida llamada sumar(), el compilador no encuentra esta función y rompe.

 

Reportar errores

Ahora bien, este tipo de errores pueden mostrarse o no en nuestro script mediante la función error_reporting(), la misma recibirá un parámetro con los errores que queremos que se muestren:

Los valores posibles son:

  • E_ERROR
  • E_WARNING
  • E_PARSE
  • E_NOTICE

También pueden ser combinados mediante el signo |:

error_reporting(E_ERROR | E_WARNING | E_PARSE);

Si queremos reportar todo tipo de errores debemos usar E_ALL:

error_reporting(E_ALL);

Y para no reportar ninguno:

error_reporting(0);

Por ejemplo en mi caso, cuando yo estoy creando una aplicación uso E_ALL, ya que nosotros deberíamos tener un control absoluto de los errores en etapa de desarrollo, y al subirlos a la web cambio ese valor por 0, porque una vez productivo nuestro sitio no debería mostrar errores de haberlos.

 

Manejo de errores

Hasta ahora nosotros vimos cómo a través de un error PHP nos muestra un mensaje por pantalla, pero nosotros también podríamos controlar esto:

Ignorar errores

Mediante el caracter @ nosotros podemos ignorar líneas de código que pudiesen llegar a devolver errores. Por ejemplo:

<?php
 $archivo = @file_get_contents('archivo_que_no_existe.txt');
 if($archivo){
    echo $archivo;
 }else{
    echo 'El archivo no ha podido ser encontrado';
 }
?>

Como se ve en el ejemplo al llamar a la función file_get_contents() y como parámetro un archivo que no existe, entonces evitamos el error que devuelve en ese punto ya que el archivo no existe:

@file_get_contents('archivo_que_no_existe.txt');

También nosotros podemos personalizar nuestros errores con excepciones. Por ejemplo podríamos crear una función para leer archivos y luego utilizar las sentencias try catch para ejecutarlo y hacer algo se produce un error:

<?php
 function leerArchivo($archivo){
    if(file_exists($archivo)){
       return file_get_contents($archivo);
    }else{
       throw new Exception('El archivo no se puede leer porque no existe.');
       return false;
    }
 }
 try{
    $texto = leerArchivo('archivo_que_no_existe.txt');
    echo $texto;
 }catch(PDOException $e){
    echo $e->getMessage();
    exit;
 }
?>

Por empezar creamos una función que intentará leer un archivo, de encontrarlo devolverá su contenido, pero sino devolverá false y creará una excepción con el mensaje ‘El archivo no se puede leer porque no existe.’ Esto de las excepciones lo veremos mucho más adelante ya que está relacionado con PHP orientado a objetos. Luego a través de la sentecia try intentamos recuperar el contenido del archivo y mostrarlo por pantalla, en el caso de catch, esto se ejecutará si encuentra un error dentro de try, en nuestro caso si el archivo no existe.

 

Gestor de errores

En el manual de PHP nosotros podremos encontrar una función para tratar los errores a nuestro gusto:

https://php.net/manual/es/function.set-error-handler.php

Por ejemplo:

<?php
 function miGestorDeErrores($errno, $errstr, $errfile, $errline) {
    if (!(error_reporting() & $errno)) {
       // Este código de error no está incluido en error_reporting
       return;
    }
    switch ($errno) {
       case E_USER_ERROR:
          echo "<b>Mi ERROR</b> [$errno] $errstr<br />\n";
          echo " Error fatal en la línea $errline en el archivo $errfile";
          echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
          echo "Abortando...<br />\n";
          exit(1);
          break;
       case E_USER_WARNING:
          echo "<b>Mi WARNING</b> [$errno] $errstr<br />\n";
          break;
       case E_USER_NOTICE:
          echo "<b>Mi NOTICE</b> [$errno] $errstr<br />\n";
          break;
       default:
          echo "Tipo de error desconocido: [$errno] $errstr<br />\n";
          break;
    }
    /* No ejecutar el gestor de errores interno de PHP */
    return true;
 }
 // establecer el gestro de errores definido por el usuario
 $gestor_errores_antiguo = set_error_handler("miGestorDeErrores");
 //Generamos un error imprimiendo una variable que no existe.
 echo $variable_que_no_existe
?>

Dentro del bloque:

switch ($errno) {
       case E_USER_ERROR:
          echo "<b>Mi ERROR</b> [$errno] $errstr<br />\n";
          echo " Error fatal en la línea $errline en el archivo $errfile";
          echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
          echo "Abortando...<br />\n";
          exit(1);
          break;
       case E_USER_WARNING:
          echo "<b>Mi WARNING</b> [$errno] $errstr<br />\n";
          break;
       case E_USER_NOTICE:
          echo "<b>Mi NOTICE</b> [$errno] $errstr<br />\n";
          break;
       default:
          echo "Tipo de error desconocido: [$errno] $errstr<br />\n";
          break;
}

Nosotros podemos cambiar el código por lo que queremos que suceda cuando se genera un error. Por ejemplo crear un archivo con el error.

 

Anterior: Aprendiendo PHP, parte 13: Trabajar con archivos

Siguiente: Aprendiendo PHP, parte 15: Importar archivos