debug.php

Basic debug utilities
git clone git://git.finwo.net/lib/debug.php
Log | Files | Refs

Debug.php (12353B)


      1 <?php
      2 
      3 namespace Finwo\Debug;
      4 
      5 class Debug
      6 {
      7 
      8 
      9     public static $dump_max_depth  = 8;
     10     public static $dump_max_length = 48;
     11     public static $output = null;
     12 
     13     /**
     14      * Prints data & overrules all output after the first call.
     15      *
     16      * Arguments: see sprintf documentation
     17      */
     18     static function printf()
     19     {
     20 
     21         // Sorry folks, this only works in development mode
     22         if (!isset($_ENV['IS_DEVEL']) || !$_ENV['IS_DEVEL']) {
     23             return;
     24         }
     25 
     26         if (isset($_SERVER['argc'])) {
     27             // Command line
     28             call_user_func_array('printf', func_get_args());
     29         } else {
     30             // Probably web instance
     31 
     32             // Init output overruling
     33             if (is_null(self::$output)) {
     34                 self::$output = '';
     35                 ob_start(function ($buffer) {
     36                     header("Content-Type: text/html");
     37 
     38                     return self::$output;
     39                 });
     40             }
     41 
     42             self::$output .= call_user_func_array('sprintf', func_get_args());
     43         }
     44     }
     45 
     46     /**
     47      * @param array   $data
     48      * @param boolean $html
     49      */
     50     static function consoleTable($data, $html = null)
     51     {
     52         $html = is_null($html) ? !isset($_SERVER['argc']) : !!$html;
     53 
     54         if ($html) {
     55             self::printf("<pre>");
     56         }
     57         $edges = array(
     58             "top-left"     => "┌─",
     59             "top"          => "─┬─",
     60             "top-right"    => "─┐",
     61             "right"        => "─┤",
     62             "bottom-right" => "─┘",
     63             "bottom"       => "─┴─",
     64             "bottom-left"  => "└─",
     65             "left"         => "├─",
     66             "horizontal"   => "─",
     67             "vertical"     => " │ ",
     68             "middle"       => "─┼─",
     69         );
     70 
     71         $column = array();
     72 
     73         // Fetch columns & their max length
     74         foreach ($data as &$row) {
     75             foreach ($row as $key => &$value) {
     76                 if (!isset($column[$key])) $column[$key] = max(4,strlen($key));
     77                 if (is_array($value)) $value = implode(',',array_values($value));
     78                 $column[$key] = max($column[$key], strlen($value));
     79             }
     80         }
     81 
     82         // Print header
     83         self::printf($edges['top-left']);
     84         self::printf(implode($edges['top'], array_map(function($length) use ($edges) {
     85             return str_repeat($edges['horizontal'], $length);
     86         },$column)));
     87         self::printf($edges['top-right']);
     88         self::printf("\n");
     89         self::printf(ltrim($edges['vertical']) . implode($edges['vertical'],array_map(function($length, $key) use ($edges) {
     90                 return $key . str_repeat(' ', $length-strlen($key));
     91             }, $column, array_keys($column))) . rtrim($edges['vertical']));
     92         self::printf("\n");
     93 
     94         // Print rows
     95         foreach ($data as $row) {
     96             // Seperator
     97             self::printf($edges['left']);
     98             self::printf(implode($edges['middle'], array_map(function($length) use ($edges) {
     99                 return str_repeat($edges['horizontal'], $length);
    100             },$column)));
    101             self::printf($edges['right']);
    102             self::printf("\n");
    103 
    104             // Data.php
    105             self::printf(ltrim($edges['vertical']));
    106             self::printf(implode($edges['vertical'], array_map(function($length, $key) use ($row) {
    107                 $data = isset($row[$key]) ? $row[$key] : 'NULL';
    108                 if (is_numeric($data)) {
    109                     return str_repeat(' ', $length-strlen($data)) . $data;
    110                 } else {
    111                     return $data . str_repeat(' ', $length-strlen($data));
    112                 }
    113             },$column,array_keys($column))));
    114             self::printf(rtrim($edges['vertical']));
    115             self::printf("\n");
    116         }
    117 
    118         // Closing
    119         self::printf($edges['bottom-left']);
    120         self::printf(implode($edges['bottom'], array_map(function($length) use ($edges) {
    121             return str_repeat($edges['horizontal'], $length);
    122         },$column)));
    123         self::printf($edges['bottom-right']);
    124         self::printf("\n");
    125 
    126         if ($html) {
    127             self::printf("</pre>");
    128         }
    129     }
    130 
    131     /**
    132      * Displays a semi-readable version of a variable.
    133      *
    134      * @param        $input
    135      * @param bool   $singleline
    136      * @param string $indent
    137      */
    138     static function dump($input, $singleline = true, $indent = '')
    139     {
    140         $html = !isset($_SERVER['argc']);
    141 
    142         $colors = array(
    143             'indent'  => '#CCC',
    144             'string'  => array(
    145                 'sys'    => '#000',
    146                 'length' => '#88F',
    147                 'value'  => '#D00',
    148             ),
    149             'integer' => array( 'value' => '#880' ),
    150             'float'   => array( 'value' => '#D44' ),
    151             'double'  => array( 'value' => '#D44' ),
    152             'boolean' => array( 'value' => '#D0D' )
    153         );
    154 
    155         $t = array(
    156             "fg" => array(
    157                 "black"   => "\e[30m",
    158                 "red"     => "\e[31m",
    159                 "green"   => "\e[32m",
    160                 "yellow"  => "\e[33m",
    161                 "blue"    => "\e[34m",
    162                 "magenta" => "\e[35m",
    163                 "cyan"    => "\e[36m",
    164                 "white"   => "\e[37m",
    165                 "default" => "\e[39m",
    166             ),
    167             "bg" => array(
    168                 "black"   => "\e[40m",
    169                 "red"     => "\e[41m",
    170                 "green"   => "\e[42m",
    171                 "yellow"  => "\e[43m",
    172                 "blue"    => "\e[44m",
    173                 "magenta" => "\e[45m",
    174                 "cyan"    => "\e[46m",
    175                 "white"   => "\e[47m",
    176                 "default" => "\e[49m",
    177             ),
    178         );
    179 
    180         $template = array(
    181             "header"        => $html ? '<div style="font-size:12px;font-family:Menlo,Monaco,Consolas,&quot;Courier New&quot;,monospace;'.(($singleline)?('white-space:nowrap;'):('')).'">' : $t['bg']['default'].$t['fg']['default'],
    182             "footer"        => $html ? '</div><br />' : $t['bg']['default'].$t['fg']['default']."\n",
    183             "type"          => $html ? '<b>%s</b>' : $t['fg']['red'].'%s'.$t['fg']['default'],
    184             "class"         => $html ? ' <i>%s</i>' : $t['fg']['blue'].' %s'.$t['fg']['default'],
    185             "count"         => ' (%s)',
    186             "linebreak"     => $html ? "<br />\n" : "\n",
    187             "too_deep"      => ' ...',
    188             "too_long"      => $html ? '<i>(%s more values)</i>' : '(%s more values)',
    189             "key"           => $html ? sprintf('[%%s] <div style="display:inline;color:%s;">_%%s</div> => ', $colors['indent']) : '[%s] _%s => ',
    190             "branch"        => array(
    191                 "default" => $html ? '<div style="display:inline;color:%s;">&nbsp;&#x251C;&#x2500;&nbsp;</div>' : ' ├─ ',
    192                 "last"    => $html ? '<div style="display:inline;color:%s;">&nbsp;&#x2514;&#x2500;&nbsp;</div>' : ' └─ ',
    193             ),
    194             "indent"        => array(
    195                 "default" => $html ? '<div style="display:inline;color:%s;">&nbsp;&#x2502;&nbsp;&nbsp;</div>' : ' │  ',
    196                 "last"    => $html ? '<div style="display:inline;color:%s;">&nbsp;&nbsp;&nbsp;&nbsp;</div>'   : '    ',
    197             ),
    198             "chars"         => array(
    199                 "space" => $html ? '&nbsp;' : ' ',
    200                 "tab"   => $html ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '    ',
    201                 "\r\n"  => $singleline ? ( $html ? sprintf('"<b style=\'color:%s;\'>&crarr;</b>"',$colors['string']['sys']) : "\\r\\n" ) : ( $html ? "<br />\n" : "\n" ),
    202                 "\r"    => $singleline ? ( $html ? sprintf('"<b style=\'color:%s;\'>&crarr;</b>"',$colors['string']['sys']) : "\\r" ) : ( $html ? "<br />\n" : "\n" ),
    203                 "\n"    => $singleline ? ( $html ? sprintf('"<b style=\'color:%s;\'>&crarr;</b>"',$colors['string']['sys']) : "\\n" ) : ( $html ? "<br />\n" : "\n" ),
    204             ),
    205             "string_length" => array(
    206                 "start" => $html ? sprintf(" <p style=\"display:inline;color:%s;\">",$colors['string']['length']) : ' '.$t['fg']['yellow'],
    207                 "value" => '%d',
    208                 "end"   => $html ? '</p>' : $t['fg']['default']
    209             ),
    210             "string_value"  => array(
    211                 "start" => $html ? sprintf(' <p style="display:inline;color:%s;">',$colors['string']['value']) : ' '.$t['fg']['green'],
    212                 "value" => '%s',
    213                 "end"   => $html ? '</p>' : $t['fg']['default'],
    214             ),
    215             "boolean_start" => $html ? sprintf(' <p style="display:inline;color:%s;">',$colors['boolean']['value']) : $t['fg']['cyan'],
    216             "boolean_value" => ' %s',
    217             "boolean_end"   => $html ? '</p>' : $t['fg']['default'],
    218             "float"         => array(
    219                 "start" => $html ? ' <p style="display:inline;color:%s;">' : ' '.$t['fg']['magenta'],
    220                 "value" => '%.3f',
    221                 "end"   => $html ? '</p>' : $t['fg']['default'],
    222             ),
    223         );
    224 
    225         $template['double']  = $template['float'];
    226         $template['integer'] = $template['float'];
    227         $template['integer']['value'] = '%d';
    228 
    229         // Sorry folks, this only works in development mode
    230         if (!isset($_ENV['IS_DEVEL']) || !$_ENV['IS_DEVEL']) {
    231             return;
    232         }
    233 
    234         if (!strlen($indent)) {
    235             self::printf($template['header']);
    236         }
    237         self::printf($template['type'], $type = gettype($input));
    238         if ($type == 'object') {
    239             self::printf($template['class'], get_class($input));
    240             $input = Data::x2array($input, self::$dump_max_depth+1);
    241         }
    242 
    243         switch ($type) {
    244             case 'object':
    245             case 'array':
    246                 self::printf($template['count'], count($input));
    247                 $length    = 0;
    248                 $keys      = array_keys($input);
    249                 $keyLength = Data::maxLength($keys);
    250                 while(count($keys)) {
    251                     $key = array_shift($keys);
    252                     self::printf($template['linebreak']);
    253                     self::printf("%s%s", $indent, sprintf($template['branch'][count($keys)?'default':'last'], $colors['indent']));
    254                     self::printf($template['key'], $key, str_repeat('_', $keyLength-strlen($key)));
    255 
    256                     if ((++$length) > self::$dump_max_length) {
    257                         self::printf($template['too_long'], $length - self::$dump_max_length);
    258                         break;
    259                     }
    260 
    261                     self::dump($input[$key], $singleline, $indent . str_replace('%s',$colors['indent'],$template['indent'][count($keys)?'default':'last']) );
    262                 }
    263                 break;
    264             case 'string':
    265                 $input = $html ? htmlspecialchars($input, ENT_QUOTES) : $input;
    266                 $input = str_replace(" ", $template['chars']['space'], $input);
    267                 $input = str_replace("\t", $template['chars']['tab'], $input);
    268                 $input = str_replace("\r\n", $template['chars']["\r\n"], $input);
    269                 $input = str_replace("\r", $template['chars']["\r"], $input);
    270                 $input = str_replace("\n", $template['chars']["\n"], $input);
    271 
    272                 self::printf($template['string_length']['start']);
    273                 self::printf($template['string_length']['value'], strlen($input));
    274                 self::printf($template['string_length']['end']);
    275 
    276                 self::printf($template['string_value']['start']);
    277                 self::printf($template['string_value']['value'], $input);
    278                 self::printf($template['string_value']['end']);
    279 
    280                 break;
    281             case 'boolean':
    282                 self::printf($template['boolean_start']);
    283                 self::printf($template['boolean_value'], $input ? 'true' : 'false');
    284                 self::printf($template['boolean_end']);
    285                 break;
    286             case 'integer':
    287             case 'float':
    288             case 'double':
    289                 self::printf($template[$type]['start'], $colors[$type]['value']);
    290                 self::printf($template[$type]['value'], $input);
    291                 self::printf($template[$type]['end']);
    292                 break;
    293         }
    294         if (!strlen($indent)) {
    295             self::printf($template['footer']);
    296         }
    297     }
    298 }