Tuesday 14 August 2018

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:
1
2
<?php
var_debug(array('a'=>new stdClass(),'b'=>array(1,2,3,4,5),new mysqli()));
Outputs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?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:
1
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.

0 comments:

Post a Comment