previousPEAR_ErrorStack (Previous) (Next) constructor PEAR_ErrorStack::PEAR_ErrorStacknext

View this page in Last updated: Sun, 18 Oct 2009
English | Brazilian Portuguese | Chinese | Dutch | French | German | Hungarian | Japanese | Polish | Russian | Spanish | Turkish

Introducción al uso de PEAR_ErrorStack para manejo avanzado de errores

Introducción al uso de PEAR_ErrorStack para manejo avanzado de errores – Usando PEAR_ErrorStack para realizar gestión de errores tanto simple como avanzada

Synopsis

Introducción al uso de PEAR_ErrorStack

Introducción

Esta clase se encuentra disponible como parte del paquete PEAR. Características incluidas:

  • Completamente testada (unit-tested) y documentada

  • Brillantemente rápida - coloca a PEAR_Error fuera del tiesto

  • Errores específicos para los paquetes

  • Niveles de error (notice/warning/error/exception)

  • Los datos del contexto de error se guardan por separado del mensaje de error

  • Errores en cascada - pueden especificarse errores padre

  • L ageneración dinámica de mensajes de error permite la generación de mensajes de error múltiples y distintos para el mismo objeto de error

  • Callbacks sofisticados están disponibles para la generación de mensajes de error, generación del contexto del error, y funcionalidad de la gestión de errores, ver Mostrar el contexto del error, Generación personalizada de mensajes de error, y controlando la generación de errores

PEAR_ErrorStack implementa el manejo y lanzamiento de error usando un patrón de pila. Esto tiene ventajs tremendas sobre la implementación de PEAR_Error. PEAR_Error centraliza toda la creación y manejo de errores en el constructor del objeto PEAR_Error. Una vez que un objeto ha sido creado, toda la gestión debe haber sido completada, incluso cuando se comprueba el valor devuelto por un método, o a través de un único callback global. Además, es casi imposible determinar la fuente de un error, y como el bagaje de toda la clase base PEAR es muy abultado, cada creación de error se ve acompañada de métodos lentos.

<?php
// uso tradicional de PEAR_Error
require_once 'PEAR.php';
class 
myobj
{
    
// no hay modo de saber de d&oacute;nde procede $err
    
function errorCallback($err)
    {
        
$this->display($err->getMessage());
        
$this->log($err->getMessage());
    }

    function 
log($msg)
    {
        
error_log($msg3'somefile.log')
    }

    function 
display($msg)
    {
        echo 
$msg '<br />';
    }
}

$myobj = new myobj;

// usiando un callback
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array(&$myobj'errorCallback'));

$ret SomePackage::doSomething();
if (
PEAR::isError($ret)) {
    
// realizar alguna manipulaci&oacute;n - este error tambi&eacute;n se muestra y se gurada en los logs
}
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);

$ret SomePackage::doSomething();
if (
PEAR::isError($ret)) {
    
// realizar alguna manipulaci&oacute;n - este error no se muestra, ni se gurada en los logs
}
PEAR::popErrorHandling();
?>

La clase PEAR_ErrorStack se ha creado en conocimiento del paquete Log, puede diferenciar fácilmente e incluso automáticamente errores de re-empaquetamiento con poca o ninguna dificultad.

<?php
// Gesti&oacute;n de errores con PEAR_ErrorStack
require_once 'PEAR/ErrorStack.php';
require_once 
'Log.php';
define('MYPACKAGE_ERROR_DBERROR'1);
class 
myobj
{
    var 
$_stack;
    function 
myobj()
    {
        
$this->_stack = &PEAR_ErrorStack::singleton('MyPackage');
    }

    function 
errorCallback($err)
    {
        switch(
$err['package']){
            case 
'MyPackage':
                
// le decimos a la pila de error que s&oacute;lo "loguee" el error
                // este no ser&aacute; colocado en la pila
                
return PEAR_ERRORSTACK_LOG;
                break;
            case 
'InternalDbPackage':
                
// re-empaquetamos estos errores como correspondientes a errores de nuestro paquete
                // para empleo final del usuario
                
$this->_stack->push(MYPACKAGE_ERROR_DBERROR'error',
                    array(
'dbmessage' => $err['message'],
                          
'dbcode' => $err['code'],
                          
'We are having Connection problems, please' .
                          
'try again in a few moments'),
                    
''$err); // incluir el eror tal como ha sido re-empaquetado
                // le decimos a la DB interna de la pila de error que ignore este error,
                // como si nunca se hubiese producido
                
return PEAR_ERRORSTACK_IGNORE;
                break;
        } 
// switch
    
}
}

$myobj = &new myobj;
// separamos las pilas de error para mi paquete, y el paquete interno DB
$dbstack = &PEAR_ErrorStack::singleton('InternalDbPackage');
$mystack = &PEAR_ErrorStack::singleton('MyPackage');
// fijamso un fichero de log empleando PEAR::Log
$log = &Log::Factory('file''somefile.log''MyPackage error log');
$mystack->setLogger($log);
// fijamos un log por defecto para emplearlo con todas las pilas de error
PEAR_ErrorStack::setDefaultLogger($log);

// los errores devueltos por MyPackage son "logueados"
$ret SomePackage::doSomething();

// Notar que $ret no necesita ser comprobado para ninguna condici&oacute;n de error - los errores est&aacute;n
// completamente separados del c&oacute;digo
if ($dbstack->hasErrors()) {
    
var_dump($dbstack->getErrors();
}

// usa el callback
$dbstack->setCallback(array(&$myobj'errorCallback'));

// cualquiera de los errores de db son transparentemente reempaquetados ahora como
// errores de MyPackage amigables con el usuario
$ret SomePackage::doSomething();

?>

�Por qué escribir una nueva rutina de gestión de errores cuando existePEAR_Error? Hay varios problemas con PEAR_Error. Si bien un mensaje de error está presente en una clase de error, procesar este mensaje de error automaticamente es excesivamente difícil para las computadoras. Además, el mensaje de error no puede traducirse fácilmente una vez ha sido colocado en PEAR_Error. No existe tampoco una utilidad estándar para guardar datos relacionados con los errores en la clase de error. Por encima de los impedimentos relacionados con mensajes de error, no hay ninguna manera de determinar automáticamente de qué paquete proviene un objeto PEAR_Error, o la gravedad de un error. Errores fatales tienen el mismo aspecto que los que no lo son tanto.

EL defecto más grande del objeto PEAR_Error es el diseño de un sólotipo de error. Cada objeto PEAR_Error e ssimplemente un objeto PEAR_Error. NO existe diferenciación basada en la severidad de un error, o su origen. El único modo de determinar la severidad es usar PEAR_ERROR_TRIGGER y las constantes E_USER_NOTICE/E_USER_WARNING/E_USER_ERROR de PHP http://www.php.net/trigger_error. Pero el uso de esta funcionalidad no justifica 900 líneas de código, simplemente porque ¡trigger_error() se encuentra dentro del propio PHP!

Ahora, para empezar a usar tu nuevo tipo de objetos de error creados, cambia todas tus llamadas aPEAR::raiseError() o PEAR::throwError() coo estas...

<?php
require_once 'PEAR.php';
// modo antiguo:
$error_specific_info 'bad';
$e PEAR::raiseError("error message - very " $error_specific_info .
    
" way to do things"MYPACKAGE_ERROR_FOO);
// otro modo antiguo:
$e PEAR::throwError("error message - very " $error_specific_info .
    
" way to do things"MYPACKAGE_ERROR_FOO);
?>

...por algo como esto:

<?php
require_once 'PEAR/ErrorStack.php';
// new way
// versi&oacute;n 1: acceso a instancias de la pila
$stack = &PEAR_ErrorStack::singleton('MyPackage');
$stack->push(MYPACKAGE_ERROR_DBERROR'error',
    array(
'query' => $query'dsn' => $dsn),
    
'Critical Database Error: Contact Administrator immediately');
// versi&oacute;n 2: acceso est&aacute;tico a singleton (ligeramente m&aacute;s lentos)
PEAR_ErrorStack::staticPush('MyPackage'MYPACKAGE_ERROR_DBERROR'error',
    array(
'query' => $query'dsn' => $dsn),
    
'Critical Database Error: Contact Administrator immediately');
?>

Para uso básico, esto es todo lo que se necesita para el uso del paquete PEAR_ErrorStack en lugar de PEAR_Error.

Características Avanzadas

Mostrando el Contexto de Errores

En algunos casos, puedes querer personalizar la gestión de errores. Por ejemplo, para muchas excepciones, es útil incluir el archivo, número de línea, y contexto de clase/función en orden a trazar un error. Está disponible una opción por defecto que será suficiente para la mayoría de los casos, y que es PEAR_ErrorStack::getFileLine().

No todos los errores de los paquetes se producen en el archivo fuente de PHP. Por ejemplo, errores en la compilación de motores de plantillas pueden producirse en los archivos fuente de las plantillas. Los errores de las bases de datos pueden ocurrir en el texto de una sentencia, o internamente al servidor de la base de datos. Los errores relacionados con paquetes de Internet pueden ocurrir en otro servidor. Todo esta información puede incluirse en un mensaje de error usando un callback que grabe el contexto.

<?php
require_once 'PEAR/ErrorStack.php';
class 
DatabaseClass
{
    var 
$_dbError;
    var 
$_dbErrorMsg;
    var 
$_dbQuery;
    var 
$_dbPos;
    
/**
     * Grabando el contexto para el paquete Database
     * @param integer C&oacute;digo de Error
     * @param array   par&aacute;metros de error pasados a {@link PEAR_ErrorStack::push()}
     * @param array   Salida de debug_backtrace() (no empleado en este callback)
     */
    
function getErrorContext($code$params$backtrace)
    {
        
$context = array(
            
'errorcode' => $this->_dbError,
            
'errormsg' => $this->_dbErrorMsg,
            
'query' => $this->_dbQuery,
            
'pos' => $this->_dbPos,
        );
        return 
$context;
    }
}
$db = new DatabaseClass;
PEAR_ErrorStack::staticSetContextCallback('Database', array(&$db'getErrorContext'));
?>

La información del contexto es formateada para ser fácilmente procesada por un aaplicación externa. Si quieres que la información del contexto esté en el error, el callback del mensaje de error debería emplearse para añadir la información en un formato legible por humanos al mensaje de error, tal y como se describe en la siguiente sección.

Generación de Mensajes de Error Personalizados

Hay tres métodos de PEAR_ErrorStack diseñados para el uso en la generación de mensajes de error eficientemente. para usarlos, debes hacer una de las dos cosas siguientes:

  • Llamar a PEAR_ErrorStack::setErrorMessageTemplate(), y fijar un mapeo de array de códigos de error a plantillas de mensajes de error, como sigue:

    <?php
    define
    ('ERROR_ONE'1);
    define('ERROR_TWO'2);
    define('ERROR_THREE'3);
    define('ERROR_FOUR'4);
    require_once 
    'PEAR/ErrorStack.php';
    $stack = &PEAR_ErrorStack::singleton('mypackage');
    $messages = array(
        
    ERROR_ONE => 'The gronk number %num% dropped a %thing%',
        
    ERROR_TWO => 'The %list% items were missing',
        
    ERROR_THREE => 'I like chocolate, how about %you%?',
        
    ERROR_FOUR => 'and a %partridge% in a pear %tree%',
    );
    $stack->setErrorMessageTemplate($messages);
    ?>

    La sustitución se hace empleando http://www.php.net/str_replace, y es muy simple. Basicamente, si un nombre de variable se encierra en signos de tanto por ciento (%), será reemplazada con el valor pasado en el array asociativo. Si un array

    <?php
    array('varname' => 'value');
    ?>
    se pasa a cualquier método, todas las ocurrencias de %varname% serán reemplazadas por el valor.

    Además, si los valores son objetos, los métodos buscarán un método llamado "__toString()" y si lo encuentran, lo usarán para convertir el objeto en una cadena. Si se pasa un error de cadenas, éstas se unirán por comas.

    <?php
    array('varname' => array('first''second''third'));
    // se convertir&aacute; en 'first, second, third'
    ?>

  • Llamar PEAR_ErrorStack::setMessageCallback(), y fijar un mensaje de error personalizado generando la función o método. Esta es probablemente la mejor opción para la mayoría de situaciones complejas, dado que permite a los usuarios sobreescribir o incluso extender el callback de error exsitente usando PEAR_ErrorStack::getMessageCallback(). Por ejemplo:

    <?php
    require_once 'PEAR/ErrorStack.php';
    class 
    foo
    {
        var 
    $_oldcallback;
        function 
    callback(&$stack$err)
        {
            
    $message call_user_func_array($this->_oldcallback, array(&$stack$err));
            
    $message .= "File " $err['context']['file'];
            return 
    $message;
        }
    }
    $a = new foo;
    $stack = &PEAR_ErrorStack::singleton('otherpackage');
    $a->_oldcallback $stack->getMessageCallback('otherpackage');
    $stack->setMessageCallback(array(&$a'callback'));
    ?>

  • Extender PEAR_ErrorStack con tu propia clase, y sobreescribir PEAR_ErrorStack::getErrorMessageTemplate() o PEAR_ErrorStack::getErrorMessage(). Para garantizar qu eesta clase será utilizada por otros paquetes/aplicaciones, usa este código justo después de la declaración de la clase:

    <?php
    PEAR_ErrorStack
    ::singleton('mypackage'falsenull'MyPEAR_ErrorStack');
    ?>

Controlando la generación de error

Hay muchos escenarios en que un control detallado sobre la generación de error es absolutamtne deseable. Un callback genérico para manejo de error significa que cada error lanzado será manejado por el mismo callback de error. Aunque PEAR_ErrorStack está diseñado para operar con callbacks independientes para cada paquete, la gestión genérica de error es posible a través del método PEAR_ErrorStack::staticPushCallback(). Esto no es diferente del modo de error de PEAR_Error, PEAR_ERROR_CALLBACK.

La autéacute;ntica fuerza de PEAR_ErrorStack procede del propio callback. El callback de PEAR_Error no tiene actualmente ningún efecto en el mensaje de error - toda la gestión de errores debe producirse en el méacute;todo empleado como callcack o en la propia función. El callback de PEAR_ErrorStack puede tener influencia sobre el error por medio del uso de tres constantes:

PEAR_ERRORSTACK_IGNORE informa a la pila para que ignore el error, como si nunca hubiese ocurrido. EL error no será ni "logueado, ni puesto en la pila. Será, no obstante, devuelto por PEAR_ErrorStack::push()

PEAR_ERRORSTACK_PUSH informa a la pila para que coloque el error en la pila de error, pero no lo loguee.

PEAR_ERRORSTACK_LOG informa a la pila para que no ponga al error en al pila de errores, y simplemente lo loguee.

<?php
define
('ERROR_CODE_ONE',1);
define('ERROR_CODE_TWO',2);
define('ERROR_CODE_THREE',3);
require_once 
'PEAR/ErrorStack.php';
require_once 
'Log.php';
function 
somecallback($err)
{
    switch(
$err['code']){
        case 
ERROR_CODE_ONE:
                return 
PEAR_ERRORSTACK_IGNORE;
                break;
        case 
ERROR_CODE_TWO:
                return 
PEAR_ERRORSTACK_PUSH;
                break;
        case 
ERROR_CODE_THREE:
                return 
PEAR_ERRORSTACK_LOG;
                break;
    } 
// switch
}
$log = &Log::factory('display');
$stack = &PEAR_ErrorStack::singleton('mypackage');
$stack->setLogger($log);
$stack->pushCallback('somecallback');
$stack->push(ERROR_CODE_ONE);
$stack->push(ERROR_CODE_TWO);
$stack->push(ERROR_CODE_THREE);
var_dump(PEAR_ErrorStack::staticGetErrors());

// simular PEAR_ERROR_CALLBACK, con un callback espec&iacute;fico para mi paquete
// cualquier otro paquete s&oacute;lo loguear&aacute; los errores, s&oacute;lamente los errores de mi paquete
// ser&aacute;n colocados en la pila de error, como condici&oacute;n
class myclass {
    function 
acallback($err)
    {
        return 
PEAR_ERRORSTACK_LOG;
    }
}
$stack2 PEAR_ErrorStack::singleton('anotherpackage');
$stack3 = &PEAR_ErrorStack::singleton('thirdpackage');
PEAR_ErrorStack::setDefaultCallback(array('myclass''acallback'));
?>

Re-empaquetando errores de un paquete a otro

El uso más obvio para un callback de error envuelve un escenario común en muchas aplicaciones de nivel de usuario que usan paquetes de nivel de sistema. Si escribes un Content Management System (CMS) con el paquete PEAR DB, es normalmente una mala idea mostrar errores de nivel de la base de datos cuando un usuario hace click en un link para añadir un mensaje a un forum. PEAR_ErrorStack puede emplearse para re-empaquetar este errror como un eror de MyPackage.

<?php
define
('MYPACKAGE_ERROR_DBDOWN',1);
require_once 
'PEAR/ErrorStack.php';
function 
repackage($err)
{
    if (
$err['package'] == 'DB') {
        
$mystack = &PEAR_ErrorStack::singleton('mypackage');
        
$mystack->push(MYPACKAGE_ERROR_DBDOWN'error', array('olderror' => $err));
        
// ignora el error de la DB, pero gu&aacute;rdalo en los errores de mi paquete, para logueado
        
return PEAR_ERRORSTACK_IGNORE;
    }
}
?>

Emulando el operador @

Una de las mayores dificultades de uso de PEAR_Error envuelve al méacute;todo PEAR::expectError(). Con errores normales de PHP, es posible silenciarlos usando el operador @ como sigue:

<?php
@file_get_contents();
?>

La emulación de este comportamiento con PEAR_ErrorStack es simple.

<?php
define
('ERROR_CODE_SOMETHING'1);
require_once 
'PEAR/ErrorStack.php';
function 
silence($err)
{
    
// ignora todos los errores
    
return PEAR_ERRORSTACK_IGNORE;
}
$stack = &PEAR_ErrorStack::singleton('mypackage');
$stack->pushCallback('silence');
$stack->push(ERROR_CODE_SOMETHING);
?>

PEAR_ErrorStack puede ir un paso más allá en este sentido, y sólo loguear errores o sólo poner errores en la pila de error, usando las otras dos constantes. Finalmente, los errores particulares pueden ser singularizados, y todos los demás ignorados.

<?php
define
('SOMEPACKAGE_ERROR_THING'1);
require_once 
'PEAR/ErrorStack.php';
function 
silenceSome($err)
{
    if (
$err['package'] != 'somepackage') {
        
// ignora todos los errores de otros paquetes
        
return PEAR_ERROR_IGNORE;
    }
    if (
$err['code'] != SOMEPACKAGE_ERROR_THING) {
        
// ignora todos los dem&aacute;s c&oacute;digos de error
        
return PEAR_ERRORSTACK_IGNORE;
    }
}
$stack = &PEAR_ErrorStack::singleton('mypackage');
$stack->pushCallback('silenceSome');
$stack->push(ERROR_CODE_SOMETHING);
?>

Compatibilidad hacia atrás con PEAR_Error, Compatibilidad hacia adelante con las Excepciones de PHP 5

PEAR_ErrorStack puede programarse para lanzar automáticamente un PEAR_Error usando PEAR::raiseError(), simplemente pasaléacute; verdadero al modo de compatibilidad con PEAR_Error como sigue:

<?php
require_once 'PEAR/ErrorStack.php';
$stack = &PEAR_ErrorStack::singleton('mypackage'falsenull'PEAR_ErrorStack'true);
?>

PEAR_ErrorStack devolverá una excepción automáticamente en PHP 5. Puedes fijar el nombre de la clase de excepción que será devuelta empleando el código siguiente:

<?php
require_once 'PEAR/ErrorStack.php';
$stack = &PEAR_ErrorStack::singleton('mypackage'falsenull'PEAR_ErrorStack'false'MyException');
?>

previousPEAR_ErrorStack (Previous) (Next) constructor PEAR_ErrorStack::PEAR_ErrorStacknext

Download Documentation Last updated: Sun, 18 Oct 2009
Do you think that something on this page is wrong? Please file a bug report or add a note.
User Notes:
There are no user contributed notes for this page.