我可以捕获 exit() 和 die() 消息吗?

发布于 2024-09-25 12:04:23 字数 423 浏览 3 评论 0原文

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

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

I'd like to be able to catch die() and exit() messages. Is this possible? I'm hoping for something similar to set_error_handler and set_exception_handler. I've looked at register_shutdown_function() but it seems to contain no context for the offending die() and exit() calls.

I realize that die() and exit() are bad ways to handle errors. I am not looking to be told not to do this. :) I am creating a generic system and want to be able to gracefully log exit() and die() if for some reason someone (not me) decides this is a good idea to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

人心善变 2024-10-02 12:04:23

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

Yes you can, but you need ob_start, ob_get_contents, ob_end_clean and 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
喜爱纠缠 2024-10-02 12:04:23

根据 PHP 手册,在死亡时仍应通知关闭函数( ) 或 exit() 被调用。

关闭功能对象析构函数将始终被执行,即使 exit( ) 被调用。

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

According to the PHP manual, shutdown functions should still be notified when die() or exit() is called.

Shutdown functions and object destructors will always be executed even if exit() is called.

It doesn't seem to be possible to get the status sent in exit($status). Unless you can use output buffering to capture it, but I'm not sure how you'd know when to call ob_start().

夏日浅笑〃 2024-10-02 12:04:23

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

Maybe override_function() could be interesting, if APD is available

眼泪淡了忧伤 2024-10-02 12:04:23

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

As best as I can tell this is not really possible. Some of the solutions posted here may work but they require a lot of additional work or many dependencies. There is no way to easily and reliable trap the die() and exit() messages.

一绘本一梦想 2024-10-02 12:04:23

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

Why do not use custom error handling instead? If not, you could always use LD_PRELOAD and C Code injection to catch it :) Or recompile php with your customizations :P

岛徒 2024-10-02 12:04:23

如果使用单点进入方法。 (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
    }
}

其他步骤和更详细:

大致是我的做法。我所做的事情比我在这里展示的还要多(处理数据库事务/回滚/发送电子邮件/编写日志/显示友好的错误消息/用户错误报告/等),但这是所有这些背后的基本思想)。< br>
希望它能帮助某人。

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

If you use the single point of entry method. (index.php) I can recommend this for your error handling:

Short version:

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

Additional steps and more detailed:

Roughly my way of doing it. I have even more going on than I show here (handling database transactions/rollback/sending e-mails/writing logs/displaying friendly error messages/user error reporting/etc), but this is the basic idea behind all of it).
Hope it helps someone.

<?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;
    }
独自←快乐 2024-10-02 12:04:23

捕获退出在自动化测试中很有用。我这样做的方法是抛出一个特殊的运行时异常,而不是直接调用 exit。

<?php

class CatchableExit extends RuntimeException
{
}

class Quitter
{
    public function run($i)
    {
        echo "Quitter called with \$i = $i \n";
        throw new CatchableExit();
    }
}

class Runner
{
    public function run()
    {
        trigger_error('I am a harmless warning', E_USER_WARNING);
        trigger_error('And I am a notice', E_USER_NOTICE);
        for ($i = 0; $i < 10; $i++) {
            $q = new Quitter();
            try {
                $q->run($i);
            } catch (CatchableExit $e) {
            }
        }
    }
}

function exception_handler(Throwable $exception)
{
    if ($exception instanceof CatchableExit) {
        exit();
    }
}

set_exception_handler('exception_handler');

$runner = new Runner();
$runner->run();

Catching exits is useful in automated tests. The way I do it is I throw a special runtime exception instead of calling exit directly.

<?php

class CatchableExit extends RuntimeException
{
}

class Quitter
{
    public function run($i)
    {
        echo "Quitter called with \$i = $i \n";
        throw new CatchableExit();
    }
}

class Runner
{
    public function run()
    {
        trigger_error('I am a harmless warning', E_USER_WARNING);
        trigger_error('And I am a notice', E_USER_NOTICE);
        for ($i = 0; $i < 10; $i++) {
            $q = new Quitter();
            try {
                $q->run($i);
            } catch (CatchableExit $e) {
            }
        }
    }
}

function exception_handler(Throwable $exception)
{
    if ($exception instanceof CatchableExit) {
        exit();
    }
}

set_exception_handler('exception_handler');

$runner = new Runner();
$runner->run();

筱果果 2024-10-02 12:04:23

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

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

yes: write a function and use that instead.

function kill($msg){
    // Do your logging..
    exit($msg);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文