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_fin= strlen($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(" ", $largo_fin - strlen($i+1)).
"</span><span style='color: $color'>".
htmlentities($codigo[$i]).'</span>';
}
return trim(join("", $salida));
}
}
}
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($handler, 23);
// Esto produce un Fatal Error
funcion_que_no_existe();
?>
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.
Saludos.