2010-10-01 52 views
23

我希望能夠趕上die()exit()消息。這可能嗎?我希望有類似於set_error_handlerset_exception_handler的東西。我查看了register_shutdown_function(),但它似乎不包含違規的die()exit()調用的上下文。我可以捕獲exit()和die()消息嗎?

我知道die()exit()是不好的方式來處理錯誤。我不希望被告知不要這樣做。 :)我正在創建一個通用系統,並希望能夠優雅地登錄exit()die()如果由於某種原因某人(而不是我)認爲這是一個好主意。

回答

4

盡我所知,這是不可能的。這裏發佈的一些解決方案可能會工作,但他們需要大量額外的工作或許多依賴項。沒有辦法容易和可靠地捕獲die()和exit()消息。

+0

嗯,它可以通過重寫腳本,而你讀它。以下示例將輸入標記爲輸入並重寫exit($ code)並將$ code代碼轉換爲php_exit($ code):編輯:stackoverflow不允許我在此處添加代碼,請參閱此文章以獲取靈感:http://stackoverflow.com /問題/ 31182968 /令牌獲得-全背到PHP源 - 如何做 – user1135940 2017-03-22 19:36:04

7

根據PHP manual,當die()或exit()被調用時仍然應該通知shutdown函數。

Shutdown functionsobject destructors即使調用exit()也會一直執行。

似乎不可能在退出狀態($狀態)中發送狀態。除非您可以使用輸出緩衝來捕獲它,但我不知道如何知道何時調用ob_start()

+3

我猜OP的問題是他希望能夠從關機功能中檢索錯誤信息。 – casablanca 2010-10-01 04:35:36

+0

正在調用shutdown函數,但是我不確定是否/如何在該點處獲取exit/die上下文。對於這個問題,我不清楚我是否知道exit/die是否是關閉函數被調用的原因。 (它看起來像是關閉函數在死時被調用,但當程序在成功運行後終止時它會被調用...) – 2010-10-01 05:24:42

5

也許override_function()可能是有趣的,如果APD可

+0

這是一個有趣的想法!不過,希望獲得更好的非APD解決方案。 – 2010-10-01 05:27:04

+0

我不認爲這會起作用。 'die'和'exit'是語言結構,而不是函數。 – 2014-03-22 21:42:58

-2

是:編寫一個函數並使用它。

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

我很欣賞這種迴應,但這根本沒有幫助。我想捕獲exit()和die(),以防某些我沒有寫的代碼調用它們。 – 2010-10-01 05:22:25

+0

我知道,但這是最接近它,只有一個新的功能和簡單的搜索和替換從出口和死亡.. – 2010-10-01 05:36:28

0

爲什麼不使用自定義錯誤處理呢?如果沒有的話,你總是可以使用LD_PRELOAD和C代碼注入來捕獲它:)或者用你的定製重新編譯php:P

7

當然可以,但你需要ob_startob_get_contentsob_end_cleanregister_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

如果您使用輸入法的單點。 (的index.php),我可以推薦這個爲你的錯誤處理:

短版:

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 
    } 
} 

額外的步驟和更詳細:

粗略我做這件事的方式。我還有更多的事情要做,我在這裏展示(處理數據庫事務/回滾/發送電子郵件/寫日誌/顯示友好的錯誤消息/用戶錯誤報告/等),但這是所有背後的基本思想)。
希望它可以幫助別人。

<?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; 
    }