开发者

Is there a Pretty Print Stack Dump?

开发者 https://www.devze.com 2023-01-26 19:56 出处:网络
Let\'s face it, debug_backtrace() output is not very pretty. Did anyone code a wrapper? And what\'s your favourite pretty var_dump() (which is usable in commercial projects, so no GPL (although LGPL

Let's face it, debug_backtrace() output is not very pretty. Did anyone code a wrapper?

And what's your favourite pretty var_dump() (which is usable in commercial projects, so no GPL (although LGPL is ok))

See also: A more pretty/informative Var_dump alternative in PHP?


Six years - and ten thousand views of this question - later, and I am still using this. It isn't pretty in a way that looks good on screen, like Kint (which is excellent).

It is plain text, which I can email to myself in in automated error reports and can display in the browser's developer console using 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开发者_StackOverflow, 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;
}


You also have kint (github repo) which has a composer package on the packagist repository

So either download the library manually or with composer, it's just a matter of :

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

Then, instead of ini_set('display_errors', 'On');, I prefer to use this simple handler in my main (first) include file :

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

With __project_env__ being set in Apache's Virtualhost (SetEnv __project_env__ "DEV") so as not to pollute the different branches of the git repository where the project lives with configuration items which are by essence environmental

  • In DEV : i get my debugging
  • In PROD, it's silent by default

Here is a screenshot of how the trace looks (each step is collapsible):

Is there a Pretty Print Stack Dump?


(source: github.io)


Here is my pretty print wrapper that is intended for non-browser output, ie error logs or the console:

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


The Xdebug extension can print stacktraces with a configurable degree of verbosity.

Is there a Pretty Print Stack Dump?

It also offers some additional var_dump() features such as syntax coloring:

Is there a Pretty Print Stack Dump?

Edit:

Regarding the inclusion of Xdebug in a commercial project.

The Xdebug license has only a few terms and seems pretty permissive.

Xdebug is a C extension. As such re-distributing it or part of it in your project may be somewhat difficult. Depending on your requirements I see a few options:

  • Have your end user install Xdebug from a Linux distribution package or a DLL from the site
  • Distribute .dll and .so files for all supported platforms
  • Have your end user build the source code
  • Distribute a custom build of PHP


jhurliman's pretty print stackTrace method above is really great. But for me it was generating lots of PHP Warnings that were also cluttering up the log. I added a little more error and type checking which results in a very nice stack trace in the logs. Here is the modified version of jhurliman's code:

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


Gonna add mine to the rest of the answers here.

If you have bootstrap and jquery installed, it's even more useful and compact, but its not neccessary.

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

I hope that helps someone. I've tried to make it as compact as possible.


Here's a "pretty print" 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>";

}


Zend_Debug::dump($var);

http://framework.zend.com/manual/en/zend.debug.html


My favorite var_dump snippet is one I made years ago and have been working on perfecting ever since. I know there are lib's out there that create really pretty fancy dumps with accordion menus and all, but I just want a simple layout, easy to read, maybe a little HTML, and as portable as a single code-snippet method can be. Thus my function:

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

Use is extremely simple. It takes infinite parameters. Also, it shows everything within simple fieldsets for each preDump called, as well as separating each parameter into its own pre tag, thus making it clean and easy to read. Each pre tag also contains a header showing the gettype of each parameter, and, if it's an object, it will also show the class name.

Use as easy as var_dump();

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

You can also use it to get the dump as a simple string and then echo when you see fit:

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

精彩评论

暂无评论...
验证码 换一张
取 消