2010-10-01 21 views
23

Me gustaría poder ver los mensajes die() y exit(). es posible? Estoy esperando algo similar a set_error_handler y set_exception_handler. Miré register_shutdown_function() pero parece que no contiene contexto para las llamadas ofensivas die() y exit().¿Puedo capturar los mensajes exit() y die()?

Me doy cuenta de que die() y exit() son malas formas de manejar los errores. No estoy esperando que me digan que no haga esto. :) Estoy creando un sistema genérico y quiero poder registrar graciosamente exit() y die() si por alguna razón alguien (no yo) decide que es una buena idea hacerlo.

Respuesta

4

Lo mejor que puedo decir es que esto no es posible. Algunas de las soluciones publicadas aquí pueden funcionar pero requieren mucho trabajo adicional o muchas dependencias. No hay forma de atrapar fácilmente los mensajes de morir() y salir().

+0

Bueno, es posible reescribiendo el script mientras lo lees. El siguiente ejemplo tokeniza la entrada y reescribe la salida ($ code) y el código $ die a php_exit ($ code): EDIT: stackoverflow no me permite agregar código aquí; consulte esta publicación para obtener inspiración: http://stackoverflow.com/questions/31182968/token-get-all-back-to-php-source-how-to – user1135940

7

De acuerdo con PHP manual, las funciones de apagado aún se deben notificar cuando se invoca die() o exit().

Shutdown functions y object destructors siempre se ejecutarán aunque se llame a exit().

Parece que no se puede obtener el estado enviado en exit ($ status). A menos que pueda usar el almacenamiento en búfer de salida para capturarlo, pero no estoy seguro de cómo saber cuándo llamar al ob_start().

+3

Supongo que el problema de OP es que le gustaría poder recuperar el mensaje de error de la función de apagado. – casablanca

+0

Se está llamando a la función de apagado, pero no estoy seguro de si puedo obtener el contexto de salida/morir en ese momento. Para el caso, no estaba claro si siquiera sabría si exit/die es el motivo de la llamada a la función de apagado. (parecía que la función de apagado se llama al morir, pero se llama cuando el proceso finaliza después de una ejecución exitosa ...) –

5

Tal override_function() podría ser interesante, si está disponible APD

+0

¡Esta es una idea interesante! Sin embargo, esperamos una mejor solución sin APD. –

+0

No creo que eso funcione. 'die' y' exit' son construcciones de lenguaje, no funciones. –

-2

Sí: crea una función y utilice en su lugar.

function kill($msg){ 
    // Do your logging.. 
    exit($msg); 
} 
+7

Agradezco la respuesta, pero esto no es útil en absoluto. Quiero capturar exit() y die() en caso de que algún código que no he escrito los llame. –

+0

lo sé, pero eso es lo más cercano que se puede llegar a él, solo una función nueva y una búsqueda simple y reemplazar desde la salida y morir para matar ... –

0

¿Por qué no utilizar el manejo de error personalizado en su lugar? Si no, siempre puedes usar LD_PRELOAD e inyección de código C para atraparlo :) O recompilar php con tus personalizaciones: P

7

Sí se puede, pero hay que ob_start, ob_get_contents, ob_end_clean y register_shutdown_function

function onDie(){ 
    $message = ob_get_contents(); // Capture 'Doh' 
    ob_end_clean(); // Cleans output buffer 
    callWhateverYouWant(); 
} 
register_shutdown_function('onDie'); 
//... 
ob_start(); // You need this to turn on output buffering before using die/exit 
@$dumbVar = 1000/0 or die('Doh'); // "@" prevent warning/error from php 
//... 
ob_end_clean(); // Remember clean your buffer before you need to use echo/print 
0

Si utiliza el único punto de método de entrada. (Index.php) Puedo recomendar esto para su gestión de errores:

versión corta:

ob_start(); 
register_shutdown_function('shutdownHandler'); 

include('something'); 

define(CLEAN_EXIT, true); 

function shutdownHandler() { 
    if(!defined("CLEAN_EXIT") || !CLEAN_EXIT) { 
     $msg = "Script stopped unexpectedly: ".ob_get_contents(); 
     //Handle premature die()/exit() here 
    } 
} 

medidas adicionales y más detalladas:

Aproximadamente mi manera de hacerlo. Tengo aún más cosas que mostrar aquí (manejo de transacciones de bases de datos/reversión/envío de correos electrónicos/registros de escritura/visualización de mensajes de error amigables/informes de errores del usuario/etc), pero esta es la idea básica detrás de todo).
Espero que ayude a alguien.

<?php 

    //Some initialization 

    //starting output buffering. (fatalErrorHandler is optional, but I recommend using it) 
    ob_start('fatalErrorHandler'); 

    //Execute code right at the end. Catch exit() and die() here. But also all other terminations inside PHPs control 
    register_shutdown_function('shutdownHandler'); 

    //handling other errors: Also optional 
    set_error_handler('errorHandler'); 



    try { 
     //Include of offensive code 
     include(...); 
    } 
    catch (Exception $ex) { 
     //Handling exception. Be careful to not raise exceptions here again. As you can end up in a cycle. 
    } 

    //Code reached this point, so it was a clean exit. 
    define(CLEAN_EXIT, true); 


    //Gets called when the script engine shuts down. 
    function shutdownHandler() { 

     $status = connection_status(); 

     $statusText = ""; 

     switch ($status) { 
      case 0: 
       if (!defined("CLEAN_EXIT") || !CLEAN_EXIT) { 
            $msg = "Script stopped unexpectedly: ".ob_get_contents(); 
        //Handle premature die()/exit() here 
       } 
       else { 
        //Clean exit. Just return 
        return; 
       } 
      case 1: $statusText = "ABORTED (1)"; break; 
      case 2: $statusText = "TIMEOUT (2)"; break; 
      case 3: $statusText = "ABORTED & TIMEOUT (3)"; break; 

      default : $statusText = "UNKNOWN ($status)"; break; 
     } 

     //Handle other exit variants saved in $statusText here 
    } 

    // error handler function (This is optional in your case) 
    function errorHandler($errno, $errstr, $errfile, $errline) { 

     $msg = "[$errno] $errstr\nOn line $errline in file $errfile"; 

     switch ($errno) { 
      case E_ERROR:    $msg = "[E_ERROR] ".$msg;    break; 
      case E_WARNING:    $msg = "[E_WARNING] ".$msg;    break; 
      case E_PARSE:    $msg = "[E_PARSE] ".$msg;    break; 
      case E_NOTICE:    $msg = "[E_NOTICE] ".$msg;    break; 
      case E_CORE_ERROR:   $msg = "[E_CORE_ERROR] ".$msg;   break; 
      case E_CORE_WARNING:  $msg = "[E_CORE_WARNING] ".$msg;  break; 
      case E_COMPILE_ERROR:  $msg = "[E_COMPILE_ERROR] ".$msg;  break; 
      case E_COMPILE_WARNING:  $msg = "[E_COMPILE_WARNING] ".$msg;  break; 
      case E_USER_ERROR:   $msg = "[E_USER_ERROR] ".$msg;   break; 
      case E_USER_WARNING:  $msg = "[E_USER_WARNING] ".$msg;  break; 
      case E_USER_NOTICE:   $msg = "[E_USER_NOTICE] ".$msg;   break; 
      case E_STRICT:    $msg = "[E_STRICT] ".$msg;    break; 
      case E_RECOVERABLE_ERROR: $msg = "[E_RECOVERABLE_ERROR] ".$msg; break; 
      case E_DEPRECATED:   $msg = "[E_DEPRECIATED] ".$msg;   break; 
      case E_USER_DEPRICIATED: $msg = "[E_USER_DEPRICIATED] ".$msg; break; 
      default:     $msg = "[UNKNOWN] ".$msg;    break; 
     } 

     //Handle Normal error/notice/warning here. 
     $handled = ... 

     if ($handled) 
      return true; //handled. Proceed execution 
     else 
      throw Exception($msg); //Be careful. this might quickly become cyclic. Be sure to have code that catches and handles exceptions. Else die() here after logging/reporting the error. 

    } 

    function fatalErrorHandler(&$buffer) { 

     $matches = null; 
     //Checking if the output contains a fatal error 
     if (preg_match('/<br \/>\s*<b>([^<>].*)error<\/b>:(.*)<br \/>$/', $buffer, $matches)) { 

      $msg = preg_replace('/<.*?>/','',$matches[2]); 

      //Handle Fatal error here 

      return "There was an unexpected situation that resulted in an error. We have been informed and will look into it." 
     } 

     //No fatal exception. Return buffer and continue 
     return $buffer; 
    } 
Cuestiones relacionadas