【问题标题】:Is it possible to get the magic constants of the caller context in php?是否可以在 php 中获取调用者上下文的魔法常量?
【发布时间】:2011-11-20 19:20:11
【问题描述】:

我想创建一个调试函数来转储有关执行上下文的信息以及其他一些信息。

在 debug.php 中,我有一个函数可以转储作为参数传递的任何内容。我对从 example.php 调用转储函数的方式感兴趣,并让它返回文件名、行号和调用上下文的函数名。

1. <?php
2. function my_function(){
3.   $var = 'My example';
4.   dump( $var );
5. }
6. ?>

example.php

我想让上面的函数输出:“example.php, my_function, 4: My example”。

是否有这样做(没有传递__FILE____FUNCTION____LINE__)作为参数?

【问题讨论】:

    标签: php constants


    【解决方案1】:

    是的,您可以使用debug_backtrace()

    它以相反的顺序(最高祖先最后)返回所有调用者和文件(包括跟踪文件)的数组。所以调用者将是数组中的第一个:

    $caller_info = next(debug_backtrace());
    

    【讨论】:

      【解决方案2】:

      PHP 的debug_backtrace():

      print_r(debug_backtrace());
      

      回溯的输出是一个关联数组的数组,这些数组命名您正在寻找的这些常量。对于this sample code,数组debug_backtrace() 返回如下所示:

      Array
      (
          [0] => Array
              (
                  [file] => /t.php
                  [line] => 9
                  [function] => abc
                  [args] => Array
                      (
                          [0] => a
                      )
      
              )
      
      )
      

      【讨论】:

        【解决方案3】:

        我也使用 debug_backtrace,我尝试处理不同的场景,这可能看起来太耗时或坏主意,但对我来说(构建我自己的小型 mvc 非常有帮助)。要处理的场景示例:

        • 退出调用者上下文时自动调用我的类的__destruct
        • 我的类的方法/析构被自动调用,因为被声明为会话处理程序
        • 我的方法/函数是从全局上下文调用的(而不是从其他函数/方法)
        • 等等..

        所有这些场景都会影响 debug_backtrace 带来的结果,我的调试函数(定义如下)试图处理这些场景。

        每个函数/方法都是这样定义的

        function my_func(){if(__DEBUG){dbg(debug_backtrace(),__CLASS__);}
        

        然后,当我想生成最终代码时,我可以运行一个简单的脚本来替换该 if 语句,例如

        a="if(__DEBUG){dbg(debug_backtrace(),__CLASS__);}"
        b="//replace_what_ever"
        dir="/var/www/mydir/"
        
        find $dir -name \*.inc -exec sed -i "s/$a/$b/g" {} \;
        find $dir -name \*.php -exec sed -i "s/$a/$b/g" {} \;
        

        至于调试功能,它可以在脚本的最后执行,比如说在 index.php 的最后。但是,如果您为会话处理程序定义了一个自己的类,那么最后一个命令将在内部执行该类的析构函数。

        因此,在大多数情况下,当出现问题时,您的调试功能会通知您。但是,如果出现致命错误,打印调试函数创建/存储的结果(存储在某个数组中,这里是 $dbg_log)的行将无法打印(例如,打印命令放在 index.php 的末尾)!!对于这种情况,您需要一个手动处理程序(仅适用于致命错误)来打印结果数组,这就是我的做法:

        register_shutdown_function('handleShutdown');
        //Catch fatal errors
        function handleShutdown() {
            $error = error_get_last();
            global $dbg_log;
            echo "<pre>";
            if(
                    $error['type'] === E_COMPILE_ERROR or
                    $error['type'] === E_ERROR or
                    $error['type'] === E_PARSE or
                    $error['type'] === E_CORE_ERROR or
                    $error['type'] === E_CORE_WARNING or
                    $error['type'] === E_RECOVERABLE_ERROR
        
            )//we need to catch fatal errors under debug
            {
                //print_r($error); if you like
                $dbg_log[] = " Tip: Start backward, the failing function (line) cannot echo a text put at the end of the function!";
                $last = count($dbg_log)-1;
                for($i=$last;$i>-1;$i--){
                    echo "$i: {$dbg_log[$i]} \n<br>";
                }
            }
        }
        

        $dbg_log 用于收集在全局上下文中定义的所有这些信息(见下文)。

        现在这是我的调试功能的样子:

        define('__DEBUG', true); // Easily switch from/to debug mode
        $dbg_log = array(); // Keep log of function calling sequence for debuging purposes
         function dbg($tr, $callee_class){
             global $dbg_log;
            // If the file of the caller exists
            if(isset($tr[0]['file'])){
                $caller = $caller=$tr[0]["file"].':'.$tr[0]["line"]; // Then we can get its name and calling line
                // If the caller is a function then it was a callee before so $tr[1] should exists
                if(isset($tr[1])){
                    // If the caller is a class method
                    if(isset($tr[1]["class"])){
                        $caller = $tr[1]["class"]."whenever->".$caller=$tr[1]["function"].':'.$caller;
                    }
                    // Else
                    else{
                        $caller = $tr[1]["function"].$caller;
                    }
                }
            }
            // Else this is an auto call by php compiler
            else{
                $caller = 'auto';
            }
            // Log the debug info
            $dbg_log[] = 'Started: '.$callee_class.'::'.$tr[0]['function'].' by '.$caller;
        }
        

        $tr (trace) 数组包含 debug_backtrace 的结果,因为它们存在于被调用函数中。另一件事要提到的是,在成为呼叫者之前,呼叫者始终是被呼叫者!

        这些是 $dbg_log 数组的输出给出的一些真实的(对你来说毫无意义,但是提供的全部信息是显而易见的)结果(在致命错误或正常退出时):

        27: Started: Framework\registry::get by App\View\WebWindowOne->__construct:/var/www/MyProject/protected/view/WebWindowOne/WebWindowOne.php:36 
        
        26: Started: App\View\WebWindowOne::__construct by Application->AppStart:/var/www/MyProject/protected/Web_Application.php:240 
        
        25: Started: Application::AppStart by Application->__construct:/var/www/MyProject/protected/Web_Application.php:150 
        
        24: Started: Framework\riskManager::__construct by Application->{closure}:/var/www/MyProject/protected/Web_Application.php:52 
        

        您定义的每个函数/方法都包含大量信息、行号、类等,只需很少的努力(只需使用此function my_func(){if(__DEBUG){dbg(debug_backtrace(),__CLASS__);})。

        【讨论】:

          猜你喜欢
          • 2012-03-29
          • 1970-01-01
          • 1970-01-01
          • 2012-08-23
          • 1970-01-01
          • 2010-12-21
          • 1970-01-01
          • 2012-04-29
          • 2014-03-18
          相关资源
          最近更新 更多