代码之家  ›  专栏  ›  技术社区  ›  Mawg says reinstate Monica

有漂亮的打印堆栈转储吗?

  •  12
  • Mawg says reinstate Monica  · 技术社区  · 14 年前

    面对现实吧, debug_backtrace() 输出不是很漂亮。有人编写包装器代码吗?

    你最喜欢什么漂亮的 var_dump() (在商业项目中可用,因此没有GPL(尽管LGPL可以)

    另请参见: A more pretty/informative Var_dump alternative in PHP?


    六年后,对这个问题有一万种看法,我仍在使用这个观点。在屏幕上看起来不好看,比如 Kint (非常好)。

    它是纯文本,我可以在自动错误报告中向自己发送电子邮件,并可以使用在浏览器的开发人员控制台中显示 ChromePhp .

    /**
     * @brief Returns an HTML formatted string showing details of the backtrace
     * 
     * Example:
     * 
     *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:48 e(373, 'beer', 'curry')
     *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:53 d(26366, 28255, 8364)
     *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:58 c()
     *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:63 b(1283, 15488, 29369)
     *    F:\Dropbox\programs\Xampp\htdocs\api\q.php:72 a(788, 6077, 25010)
     */
    function FormatBacktrace()
    {
       $result = '<h4>Backtrace</h4>';
    
       foreach (debug_backtrace() as $trace)
       {
          if ($trace['function'] ==__FUNCTION__)
              continue;
    
          $parameters = is_array($trace['args']) ? implode(", ",$trace['args']) : "";
    
          if (array_key_exists('class', $trace))
             $result .= sprintf("%s:%s %s::%s(%s)<br>",   
                                  $trace['file'],   
                                  $trace['line'],    
                                  $trace['class'],  
                                  $trace['function'],  
                                  $parameters);
          else
             $result .= sprintf("%s:%s %s(%s)<br>", 
                                  $trace['file'], 
                                  $trace['line'], 
                                  $trace['function'], 
                                  $parameters);
        }
    
        return $result;
    }
    
    8 回复  |  直到 5 年前
        1
  •  6
  •   Alex Jasmin    14 年前

    这个 Xdebug extension 可以 print stacktraces 具有可配置的详细程度。

    Xdebug stacktrace image

    它还提供一些 additional var_dump() features 例如语法着色:

    Colored var_dump()

    编辑:

    关于将xdebug包含在商业项目中。

    这个 Xdebug license 只有几个条件,似乎相当宽容。

    xdebug是C扩展。因此,在您的项目中重新分配它或它的一部分可能有些困难。根据您的要求,我看到一些选项:

    • 让最终用户从Linux分发包或站点的dll安装xdebug
    • 为所有支持的平台分发.dll和.so文件
    • 让最终用户构建源代码
    • 分发自定义的PHP版本
        2
  •  9
  •   Community Doug McClean    7 年前

    你也有 kint ( github repo )它有一个 composer 上的包 packagist 存储库

    因此,要么手动下载库,要么使用 作曲家 ,这只是一个问题:

    $ composer init
    $ composer require raveren/kint
    $ composer install
    

    然后,而不是 ini_set('display_errors', 'On'); ,我更喜欢在主(第一个)include文件中使用这个简单的处理程序:

    if (  getenv('__project_env__') === 'DEV') {
    
      error_reporting(E_ALL | E_STRICT);
    
      function shutdown_handler() {
        $error = error_get_last();
        Kint::trace();
        Kint::dump($error);
      }
      register_shutdown_function('shutdown_handler');
    
    } else {
     ...
    }
    

    __project_env__ 设置在Apache的虚拟主机中( SetEnv __project_env__ "DEV" )以免污染 git 项目所在的存储库中包含的配置项本质上是 environmental

    • 我得到了我的调试
    • 在prod中,默认情况下是无声的。

    以下是跟踪外观的屏幕截图(每个步骤都是可折叠的):

    Kint stack trace

        3
  •  5
  •   jhurliman    12 年前

    以下是我的漂亮打印包装,用于非浏览器输出,即错误日志或控制台:

    function stackTrace() {
        $stack = debug_backtrace();
        $output = '';
    
        $stackLen = count($stack);
        for ($i = 1; $i < $stackLen; $i++) {
            $entry = $stack[$i];
    
            $func = $entry['function'] . '(';
            $argsLen = count($entry['args']);
            for ($j = 0; $j < $argsLen; $j++) {
                $func .= $entry['args'][$j];
                if ($j < $argsLen - 1) $func .= ', ';
            }
            $func .= ')';
    
            $output .= $entry['file'] . ':' . $entry['line'] . ' - ' . $func . PHP_EOL;
        }
        return $output;
    }
    
        4
  •  3
  •   jambroseclarke    9 年前

    上面的Jhurliman漂亮的打印stacktrace方法真的很棒。但对我来说,它产生了大量的PHP警告,这些警告也把日志弄得一团糟。我添加了更多的错误和类型检查,这会在日志中产生非常好的堆栈跟踪。下面是Jhurliman代码的修改版本:

    function stackTrace() {
        $stack = debug_backtrace();
        $output = '';
    
        $stackLen = count($stack);
        for ($i = 1; $i < $stackLen; $i++) {
            $entry = $stack[$i];
    
            $func = $entry['function'] . '(';
            $argsLen = count($entry['args']);
            for ($j = 0; $j < $argsLen; $j++) {
                $my_entry = $entry['args'][$j];
                if (is_string($my_entry)) {
                    $func .= $my_entry;
                }
                if ($j < $argsLen - 1) $func .= ', ';
            }
            $func .= ')';
    
            $entry_file = 'NO_FILE';
            if (array_key_exists('file', $entry)) {
                $entry_file = $entry['file'];               
            }
            $entry_line = 'NO_LINE';
            if (array_key_exists('line', $entry)) {
                $entry_line = $entry['line'];
            }           
            $output .= $entry_file . ':' . $entry_line . ' - ' . $func . PHP_EOL;
        }
        return $output;
    }
    
        5
  •  1
  •   philfreo    14 年前

    这里有一个“漂亮的印刷品”var_dump

    function vdump() {
    
        $args = func_get_args();
    
        $backtrace = debug_backtrace();
        $code = file($backtrace[0]['file']);    
    
        echo "<pre style='background: #eee; border: 1px solid #aaa; clear: both; overflow: auto; padding: 10px; text-align: left; margin-bottom: 5px'>";
    
        echo "<b>".htmlspecialchars(trim($code[$backtrace[0]['line']-1]))."</b>\n";
    
        echo "\n";
    
            ob_start();
    
                foreach ($args as $arg)
                    var_dump($arg);
    
                $str = ob_get_contents();
    
            ob_end_clean();
    
            $str = preg_replace('/=>(\s+)/', ' => ', $str);
            $str = preg_replace('/ => NULL/', ' &rarr; <b style="color: #000">NULL</b>', $str);
            $str = preg_replace('/}\n(\s+)\[/', "}\n\n".'$1[', $str);
            $str = preg_replace('/ (float|int)\((\-?[\d\.]+)\)/', " <span style='color: #888'>$1</span> <b style='color: brown'>$2</b>", $str);
    
            $str = preg_replace('/array\((\d+)\) {\s+}\n/', "<span style='color: #888'>array&bull;$1</span> <b style='color: brown'>[]</b>", $str);
            $str = preg_replace('/ string\((\d+)\) \"(.*)\"/', " <span style='color: #888'>str&bull;$1</span> <b style='color: brown'>'$2'</b>", $str);
            $str = preg_replace('/\[\"(.+)\"\] => /', "<span style='color: purple'>'$1'</span> &rarr; ", $str);
            $str = preg_replace('/object\((\S+)\)#(\d+) \((\d+)\) {/', "<span style='color: #888'>obj&bull;$2</span> <b style='color: #0C9136'>$1[$3]</b> {", $str);
            $str = str_replace("bool(false)", "<span style='color:#888'>bool&bull;</span><span style='color: red'>false</span>", $str);
            $str = str_replace("bool(true)", "<span style='color:#888'>bool&bull;</span><span style='color: green'>true</span>", $str);
    
            echo $str;
    
        echo "</pre>";
    
        echo "<div class='block tiny_text' style='margin-left: 10px'>";
    
            echo "Sizes: ";
            foreach ($args as $k => $arg) {
    
                if ($k > 0) echo ",";
                echo count($arg);
    
            }
    
        echo "</div>";
    
    }
    
        6
  •  1
  •   karim79    14 年前
        7
  •  1
  •   Chud37    6 年前

    把我的加在剩下的答案里。

    如果您安装了引导程序和jquery,它会更有用、更紧凑,但它不是必需的。

    function prettyPrintBackTrace() {
        $backtrace = "\n<b><u>Full Backtrace</u></b>\n<script>function toggleBackTraceTwirl(self) {\$('span', self).toggleClass('glyphicon-menu-up glyphicon-menu-down');}</script>";
        foreach (debug_backtrace() as $key => $trace) {
            if(($trace['function'] ==__FUNCTION__) || ($trace['function'] == "fail")) {continue;}
            $class = (array_key_exists('class', $trace) ? "class <u>({$trace['class']})</u>" : false);
            $exp = explode("/",$trace['file']);
            $exp[count($exp)-1] = "<b>" . end($exp) . "</b>";;
            $filename = implode("/",array_splice($exp, -4));    
            $backtrace .=  "/{$filename}:{$trace['line']}, ";
            if((isset($trace['args'])) && (is_array($trace['args']))) {
    
    
                if( (is_string($trace['args'][0])) && (substr($trace['args'][0],-4) == ".php") && (count($trace['args'] == 1)) ) {
                    // It was most likely a php include of some sort.
                    $exp = explode("/",$trace['args'][0]);
                    $filename = implode("/",array_splice($exp, -2));
                    $backtrace .= "function <i>{$trace['function']}(<b>{$filename}</b>)</i>\n";
                } else { 
                    // Finish the line and move on.
                    $backtrace .= "function <i>{$trace['function']}()</i>&nbsp;<a href='#' data-target='#backtraceparameters{$key}' onClick='toggleBackTraceTwirl(this)' data-toggle='collapse'><span class='glyphicon glyphicon-menu-down'></span></a>\n";
                    $backtrace .=  "<div id='backtraceparameters{$key}' class='collapse'>";
                    $args = array();
                    foreach($trace['args'] as $key => $val) {
                        if($val) $args[(!is_numeric($key) ? "key" : false)] = $val;
                    }
                    foreach($args as $count =>  $a) {
                        $backtrace .= ($count != (count($args) -1) ? "&boxvr;" : "&boxur;");
                        $value = $a;
                        if($a === true) $value = "<i>true</i>";
                        if($a === false) $value = "<i>f alse</i>";
                        $backtrace .= "&boxh; ".(!is_numeric($count) ? $count." " : false).var_export($value,1)."\n";
                    }
                    $backtrace .=  "</div>";
                }
            }
        }
        return $backtrace;
    }
    

    我希望这能帮助别人。我已经尽力使它尽可能紧凑。

        8
  •  0
  •   SpYk3HH    11 年前

    我最喜欢的 var_dump 这个片段是我多年前做的,从那以后一直在努力完善。我知道有一些lib可以用手风琴菜单创建非常漂亮的转储文件,但是我只想要一个简单的布局,易于阅读,也许有一点HTML,并且可以像一个代码片段方法那样进行移植。因此我的职能:

    function preDump() {    //  use string "noEcho" to just get a string return only
        $args = func_get_args();
        $doEcho = TRUE; $sb;
        if ($args) {
            $sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;padding:0em 3em 1em 1em;"><legend><b>preDump: '.count($args).' Parameters Found.</b></legend>';
            foreach (func_get_args() as $arg) {
                if (gettype($arg) == 'string') if ($arg == 'noEcho') { $doEcho = FALSE; $sb = preg_replace('/(preDump: )[0-9]+/', 'preDump: '.(count($args)-1), $sb); continue; }
                $sb .= '<pre data-type="'.gettype($arg).'"';
                switch (gettype($arg)) {
                    case "boolean":
                    case "integer":
                        $sb .= ' data-dump="json_encode"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
                        $sb .= json_encode($arg);
                        break;
                    case "string":
                        $sb .= ' data-dump="echo"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
                        $sb .= $arg;
                        break;
                    default:
                        $sb .= ' data-dump="var_dump"';
                        if (is_object($arg)) $sb .= 'data-class="'.get_class($arg).'"';
                        $sb .= '><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')';
                        if (is_object($arg)) $sb .= ' ['.get_class($arg).']';
                        $sb .= '</b></p><p>';
                        ob_start();
                        var_dump($arg);
                        $sb .= ob_get_clean();
                        if (ob_get_length()) ob_end_clean();
                }
                $sb .= '</p></pre>';
            }
            $sb .= '</fieldset></div>';
        }
        else {
            $sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;"><legend><b>preDump: [ERROR]</b></legend><h3>No Parameters Found</h3></fieldset></div>';
        }
        if ($doEcho) echo($sb);
        return $sb;
    }
    

    使用非常简单。它需要无限的参数。同时,它显示了简单的 fieldsets 为每个 preDump 调用,并将每个参数分离为自己的参数 pre 标签,使其干净易读。各 之前 标记还包含显示 gettype 对于每个参数,如果它是一个对象,它还将显示 class name .

    使用起来像 var_dump();

    preDump(TRUE, 101, 'this is a string', array( 'array', 'here' ), (object)array ( 'this' => 'is', 'an' => 'object' ), $someXMLvariable);
    

    您还可以使用它将转储作为一个简单的字符串,然后在您认为合适时进行回声处理:

    $bob = preDump($someParam1, $someParam2, 'noEcho'); // 'noEcho' causes it to return as string only