A smart alternative to PHP’s “var_dump” function

The “var_debug” function is a smart alternative to PHP’s “var_dump” function, which limits the output and prints the file path and line of the invocation.

The problem with “var_dump”

It may output so much information that it locks up your browser (and your web server thread). This is very annoying and not very useful either, since there is no way you are ever going to read all the information. And when you sprinkle your code with “var_debug” function calls during a debug session, you sometimes lose track of which call produced the output you are currently looking at.

File path and line of invocation

The “var_debug” function outputs the file path and line number of the invocation. So even when your “var_dump” calls all say the same you can still see what happened. To accomplish this, it uses the PHP “debug_backtrace” function. It sets the “DEBUG_BACKTRACE_IGNORE_ARGS” option to reduce memory usage. From the produced backtrace, it gets the first element that holds a file path and line number and it adds that to the start of the output.

Usage example

The following:

<?php
var_debug(array('a'=>new stdClass(),'b'=>array(1,2,3,4,5),new mysqli()));

Outputs:

/home/maurits/public_html/debug.php:2
array(3)
{
  [a] => stdClass#1
  {
  }
  [b] => array(5)
  {
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
  }
  [0] => mysqli#2
  {
    [affected_rows] => null
    [client_info] => null
    [client_version] => null
    [connect_errno] => null
    [connect_error] => null
    [errno] => null
    [error] => null
    [field_count] => null
    [host_info] => null
    [info] => null
    [insert_id] => null
    [server_info] => null
    [server_version] => null
    [stat] => null
    [sqlstate] => null
    [protocol_version] => null
    [thread_id] => null
    [warning_count] => null
  }
}

Limit the output

The “var_debug” function limits the output with the following default rules:

  1. Only the first 100 characters of each string are logged (full length is shown)
  2. Only the first 25 elements of an array are logged (full length is shown)
  3. Only the first 10 levels of nested objects/arrays are logged

These three limits can be set using three optional parameters in the above order. Hence, calling “var_debug($variable)” is equal to calling “var_debug($variable,100,25,10)”.

Use the source

            <?php
            function var_debug($variable,$strlen=100,$width=25,$depth=10,$i=0,&$objects = array())
            {
              $search = array("\0", "\a", "\b", "\f", "\n", "\r", "\t", "\v");
              $replace = array('\0', '\a', '\b', '\f', '\n', '\r', '\t', '\v');

              $string = '';

              switch(gettype($variable)) {
                case 'boolean':      $string.= $variable?'true':'false'; break;
                case 'integer':      $string.= $variable;                break;
                case 'double':       $string.= $variable;                break;
                case 'resource':     $string.= '[resource]';             break;
                case 'NULL':         $string.= "null";                   break;
                case 'unknown type': $string.= '???';                    break;
                case 'string':
                  $len = strlen($variable);
                  $variable = str_replace($search,$replace,substr($variable,0,$strlen),$count);
                  $variable = substr($variable,0,$strlen);
                  if ($len<$strlen) $string.= '"'.$variable.'"';
                  else $string.= 'string('.$len.'): "'.$variable.'"...';
                  break;
                case 'array':
                  $len = count($variable);
                  if ($i==$depth) $string.= 'array('.$len.') {...}';
                  elseif(!$len) $string.= 'array(0) {}';
                  else {
                    $keys = array_keys($variable);
                    $spaces = str_repeat(' ',$i*2);
                    $string.= "array($len)\n".$spaces.'{';
                    $count=0;
                    foreach($keys as $key) {
                      if ($count==$width) {
                        $string.= "\n".$spaces."  ...";
                        break;
                      }
                      $string.= "\n".$spaces."  [$key] => ";
                      $string.= var_debug($variable[$key],$strlen,$width,$depth,$i+1,$objects);
                      $count++;
                    }
                    $string.="\n".$spaces.'}';
                  }
                  break;
                case 'object':
                  $id = array_search($variable,$objects,true);
                  if ($id!==false)
                    $string.=get_class($variable).'#'.($id+1).' {...}';
                  else if($i==$depth)
                    $string.=get_class($variable).' {...}';
                  else {
                    $id = array_push($objects,$variable);
                    $array = (array)$variable;
                    $spaces = str_repeat(' ',$i*2);
                    $string.= get_class($variable)."#$id\n".$spaces.'{';
                    $properties = array_keys($array);
                    foreach($properties as $property) {
                      $name = str_replace("\0",':',trim($property));
                      $string.= "\n".$spaces."  [$name] => ";
                      $string.= var_debug($array[$property],$strlen,$width,$depth,$i+1,$objects);
                    }
                    $string.= "\n".$spaces.'}';
                  }
                  break;
              }

              if ($i>0) return $string;

              $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
              do $caller = array_shift($backtrace); while ($caller && !isset($caller['file']));
              if ($caller) $string = $caller['file'].':'.$caller['line']."\n".$string;

              echo $string;
            }

Modifications

If you would like the function to echo HTML-printable output, you can replace the last line that says “echo $string;” with the following:

echo nl2br(str_replace(' ','&nbsp;',htmlentities($string)));

Replace “echo $string;” with “return $string;” if you want to use the output for logging purposes in some other function.

Alternatives

This post has turned out to be rather popular on Reddit. Here are some alternatives that might also deserve your attention:

All of them seem like good alternatives. The thing that possibly makes “var_debug” stand out is its simplicity: It is one function that you can easily copy-paste. Use the comments and let me know what works (best) for you.

19 Responses to “A smart alternative to PHP’s “var_dump” function”

  • you can also dump the content of a variable in a file with
    file_put_contents(‘/tmp/log’, var_export($mybigvar, 1));
    and after that use some grep functions to find the output you are interested in.

  • Maurits van der Schee (Innovation Engineer):

    @razvan: Thanks, good approach. That will also work fine!

  • Scott:

    Well, someone hasn’t heard of print_r…

  • raveren:

    Please do not advise people to use Krumo. It’s full of bugs and abandoned for over 5 years.

  • KingCrunch:

    Seriously: Join us in the 21th century and use a _debugger_.

  • SenseException:

    You can add the function via Composer to your Dev environment to be able to use it in your project.

  • Maurits van der Schee (Innovation Engineer):

    @raveren: I disagree. Last Update: 2013-04-26. See: http://sourceforge.net/projects/krumo/

  • raveren:

    @Maurits : Did you even download the package? The date listed is some last action on sourceforge. Even the class.krumo.php header says

    @version $Id: class.krumo.php 22 2007-12-02 07:38:18Z Mrasnika $

  • Maurits van der Schee (Innovation Engineer):

    @raveren: A class not being changed does not mean the project is abandoned, especially on a project like this. Can you give other/better reasons for people not to use krumo? Are there, for example, many critical defects that are not addressed?

  • Robbo:

    > title says smart
    > makes 72 line function
    > on website that looks like it is from 2000

    I don’t even.

  • raveren:

    @Maurits : you can’t be serious, 6 years, ESPECIALLY on a project like this, is not being abandoned? You wrote a cute little function and you think it’s that easy?

    Please, run this code:

    “`
    $a = “<script>alert()</script>”;
    var_debug( $GLOBALS );
    “`

    And you’ll see *3* problems with your code just right there, not to mention, it doesn’t run at all on php 5.4 and is in almost all conceivable ways worse than var_dump. Should I elaborate on this statement? Easily, but I’ll have to write more than 72 lines then.

    I’m sorry, but I can’t not be harsh on people who pretend to know what they’re talking about.

  • Maurits van der Schee (Innovation Engineer):

    @raveren: Ah, so I figured it out.. You are the author of Kint. Congratulations on your great open-source project, honestly.

    And you may be right.. Kint may be “a superior replacement for Krumo”. Still not arguing with you.. period.

  • Thanks for not taking it the wrong way, it might seem like a trivial task to an onlooker, but just take a glance at the object parser code in Kint:

    https://github.com/raveren/kint/blob/1.0.0-wip/parsers/parser.class.php#L344

    it’s 120 lines with references to a myriad of other methods just to parse a generic object. Each line is a product of research into PHPs intricacies and counltess hours of experimenting and real world usage. And there are still new things I find every week.

    Furthermore, some objects need a representation that’s tailored for their type, as just listing their properties does not help to see what they’re about. It’s all just to deliver the 100% of useful information in the most informative way to the user.

    Then there’s presentability, usage, installation, compatibility with PHP versions and dozens upon dozens of stuff you have to take into consideration. And finally, this IS php we’re talking about, it’s full of black magic and plain weird stuff, I’m still afraid to look at the code I had to summon to take care of the super-super-super global variable $GLOBALS. Don’t even ask :)

    You can’t just finish a project like that, it’s never done – and not updating it for 6 years is like having never done anything.

    Also, I don’t hide my identity when I discourage use of Krumo: https://github.com/oodle/krumo/issues/9#issuecomment-27317047 I just did not see how it mattered here…

  • Just:

    what about LadyBug from RaulFraile? https://github.com/raulfraile/Ladybug

  • Maurits van der Schee (Innovation Engineer):

    @Just: Thank you for the link!

  • Shimshon:

    I am getting this error:

    “Fatal error: Call-time pass-by-reference has been removed”

    For this line of code:

    $string.= var_debug($variable[$key],$strlen,$width,$depth,$i+1,&$objects);

    I have PHP 5.5.12 running on Arch. Do you have a suggestion?

  • Maurits van der Schee (Innovation Engineer):

    @Shimson: Thank you, post updated :-)

  • woof:

    Really, not a single comment in the code? Smells like QUALITY. I’m surprised you even used white space.

  • Maurits van der Schee (Innovation Engineer):

    @woof: Thank you for your comment. I realize there are some code smells to it.

Leave a Reply