【问题标题】:Can I catch exit() and die() messages?我可以捕获 exit() 和 die() 消息吗?
【发布时间】:2011-04-19 16:31:20
【问题描述】:

我希望能够捕获 die()exit() 消息。这可能吗?我希望有类似于set_error_handlerset_exception_handler 的东西。我查看了register_shutdown_function(),但它似乎没有包含违规die()exit() 调用的上下文。

我意识到die()exit() 是处理错误的糟糕方法。我不希望被告知不要这样做。 :) 我正在创建一个通用系统,并且希望能够优雅地记录 exit()die() 如果由于某种原因有人(不是我)认为这是一个好主意。

【问题讨论】:

    标签: php die


    【解决方案1】:

    可以,但您需要 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
    

    【讨论】:

      【解决方案2】:

      根据PHP manual,在调用 die() 或 exit() 时仍应通知关闭函数。

      Shutdown functionsobject destructors 将始终被执行,即使 exit() 被调用。

      似乎无法获取exit($status) 中发送的状态。除非您可以使用输出缓冲来捕获它,但我不确定您如何知道何时调用 ob_start()

      【讨论】:

      • 我猜 OP 的问题是他希望能够从关闭函数中检索错误消息。
      • 正在调用关闭函数,但我不确定是否/如何获得退出/死亡上下文。就此而言,尚不清楚我是否知道 exit/die 是否是调用关闭函数的原因。 (看起来关闭函数是在死机上调用的,但是当进程在成功运行后终止时也会调用它......)
      【解决方案3】:

      如果 APD 可用,override_function() 可能会很有趣

      【讨论】:

      • 这是一个有趣的想法!不过,希望有更好的非 APD 解决方案。
      • 我认为这行不通。 dieexit 是语言结构,而不是函数。
      【解决方案4】:

      据我所知,这是不可能的。此处发布的一些解决方案可能有效,但它们需要大量额外工作或许多依赖项。没有办法轻松可靠地捕获 die() 和 exit() 消息。

      【讨论】:

      • 嗯,可以在阅读时重写脚本。以下示例标记输入并将 exit($code) 和 die $code 重写为 php_exit($code): 编辑:stackoverflow 不允许我在此处添加代码,请参阅这篇文章以获取灵感:stackoverflow.com/questions/31182968/…
      【解决方案5】:

      为什么不使用自定义错误处理来代替?如果没有,您总是可以使用 LD_PRELOAD 和 C 代码注入来捕获它:) 或者使用您的自定义重新编译 php:P

      【讨论】:

        【解决方案6】:

        如果您使用单点进入方法。 (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 ob_get_contents() can have additional useful information 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;
            }
        

        【讨论】:

          【解决方案7】:

          是的:编写一个函数并使用它。

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

          【讨论】:

          • 感谢您的回复,但这根本没有帮助。如果我没有编写的某些代码调用它们,我想捕获 exit() 和 die()。
          • 我知道,但这是你能得到的最接近它的,只有一个新功能和一个简单的搜索和替换从退出和死去杀死..
          猜你喜欢
          • 2020-08-18
          • 2014-07-17
          • 1970-01-01
          • 2014-10-08
          • 2011-06-01
          • 1970-01-01
          • 2010-12-20
          • 2011-03-11
          相关资源
          最近更新 更多