Ver Mensaje Individual
  #1 (permalink)  
Antiguo 21/09/2003, 02:56
Avatar de Webstudio
Webstudio
Colaborador
 
Fecha de Ingreso: noviembre-2001
Ubicación: 127.0.0.1
Mensajes: 3.499
Antigüedad: 23 años, 2 meses
Puntos: 69
Manejo de Errores en PHP (POO)

Bueno, digamos que tuve una noche "agitada" y mientras estaba comenzando a desarrollar unas clases que van a formar parte del NokTemplates2, descubrí que necesitaba algún tipo de "manejo de errores" para una aplicación. Dado que PHP4 aún no tiene soporte para Excepciones ( que si tendrá PHP5 ) se me dio por hacer un objeto que administre los errores, pero quería que esto se hiciera automáticamente, o sea, nada de estar indicando $objError->error("algo salió mal"); sino que queria utilizar las funciones que nos da PHP actualmente para el manejo de los errores.

Así que leyendo entre algunas cosas que recordaba, y revisando en los comentarios de PHP.net, conseguí implementar un truquito para "atrapar" errores Fatales ( que a set_error_handler se le escapan ).

Es así que terminé con una clase simple, que les comparto, para que la puedan estudiar, darme sus opiniones, sugerir mejoras, etc. El "Sistemita" está compuesto de 2 clases, AdminError y Contexto, este es el código de los mismos:
Código PHP:
class AdminError
{
    function 
AdminError()
    {
        function 
adm_error($numero$mensaje$archivo$linea$contexto$retorna=0)
        {
            
$objContexto = new Contexto($numero$mensaje$archivo$linea$contexto);
            if(
$retorna
                return 
$objContexto->leer();
            else
                print 
$objContexto->leer();
        }
        
        function 
errorFatal($buffer)
        {
            
$buffer_temporal $buffer;
            
$texto strip_tags($buffer_temporal);
            if(
preg_match('/Fatal error: (.+) in (.+)? on line (\d+)/'$texto$c))
                return 
adm_error(E_USER_ERROR$c[1], $c[2], $c[3], ""true);
            return 
$buffer;
        }
        
ob_start('errorFatal');
        
set_error_handler('adm_error');
    }
}

/** 
 * Clase Contexto
 * Devuelve el contexto de la linea de un archivo.
 *
 **/
class Contexto
{
    
/**
     * Atributo
     *
     **/
    
    
var $_numero "";
    
    
/**
     * Atributo
     *
     **/
    
    
var $_mensaje "";
    
    
/**
     * Atributo
     *
     **/
    
    
var $_lineas 5;

    
/**
     * Constructor
     * @access protected
     */
    
function Contexto($numero$mensaje$archivo$linea$contexto)
    {
        
$this->_mensaje "
        <b>Error:</b> $mensaje<br><hr>
        <b>Archivo:</b> $archivo<br><hr>
        <b>Línea:</b> $linea<br><hr>
        <b>Contexto del Código:</b><br><pre>"
.
        
$this->obtenerContexto($archivo, (int) $linea)."</pre><hr>";
    }
    
    
/**
     *
     * @access public
     * @return void 
     **/
    
function leer()
    {
        return 
$this->_mensaje;
    }
    
    
/**
     *
     * @access public
     * @return void 
     **/
    
function obtenerContexto($archivo$linea)
    {
        if (!
file_exists($archivo)) 
        { 
            
//  Nos fijamos que el archivo exista
            
return "El contexto no puede mostrarse - ($archivo) no existe"
        } elseif ((!
is_int($linea)) OR ($linea <= 0)) { 
            
//  Verificamos que el numero de linea sea válido
            
return "El contexto no puede mostrarse - ($linea) es un número inválido de linea"
        } else {
            
//  leemos el codigo
            
$codigo file$archivo );
            
$lineas count($codigo);

            
//  calculamos los numeros de linea
            
$inicio $linea $this->_lineas
            
$fin $linea $this->_lineas
            
//  verificaciones de seguridad
            
if ($inicio 0$inicio 0;
            if (
$fin >= $lineas$fin $lineas;
            
$largo_finstrlen($fin) + 2;
            
            for (
$i $inicio-1$i $fin$i++)
            { 
                
//  marcamos la linea en cuestion.
                
$color=($i==$linea-1?"red":"black");
                
$salida[] = "<span style='background-color: lightgrey'>".($i+1).
                            
str_repeat("&nbsp;"$largo_fin strlen($i+1)).
                            
"</span><span style='color: $color'>".
                            
htmlentities($codigo[$i]).'</span>';
            } 
            return 
trim(join(""$salida)); 
        }
    }

Un Scrip de ejemplo, para mostrar el úso de la clase, es el siguiente:
Código PHP:
<?php
// activamos todos los errores
error_reporting(E_ALL);

include(
'./clases/class.AdminError.php');

$error = new AdminError;
// Esto produce dos Notices
echo $data[constante_que_no_existe];
// Esto produce un Warning
$handler "No soy un handler adecuado";
$data fgets($handler23);
// Esto produce un Fatal Error
funcion_que_no_existe();
?>
Primero, si hay un Fatal Error, solo va a mostrar ESE Fatal Error hasta que sea arreglado. Luego, si el script solo contiene Warnings o Notices los muestra todos juntos, junto a la linea que provoca el error y ( por defecto ) las 5 lineas anteriores y posteriores a la linea "conflictiva".

Que queda por hacer? Ufff.. muchisimas cosas:
  • Aún el objeto no atrapa errores del Tipo "Parse Error"
  • No atrapa Fatal Errors provocados por las clases AdminError y Contexto
  • Me gustaria que el coigo se mostrara como highlight_string, pero no puedo por ser una funcion "handler" de output_buffering.
  • Como no puedo utilizar ob_start, no puedo mostrar los contenidos de la variable "$contexto" para dar una idea del estado de las variables al momento de creado el error.
  • Algo más que se me ocurra en el camino.
Espero que no se hayan aburrido con un Post tan largo y específico. Espero que esta idea del trabajo con Errores les agrade, y sino, por favor, muestren sus técnicas para el trabajo de este tipo.

Saludos.
__________________
Tutoriales Photoshop | Web-Studio.com.ar
Artículos PHP | ZonaPHP.com