Passed
Push — main ( 4b3ca1...3077d4 )
by Sammy
01:28
created

Debugger   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Importance

Changes 22
Bugs 3 Features 1
Metric Value
eloc 92
c 22
b 3
f 1
dl 0
loc 176
rs 9.76
wmc 33

13 Methods

Rating   Name   Duplication   Size   Complexity  
A setSkipClasses() 0 6 2
A purgeTraces() 0 11 4
A visualDump() 0 19 2
A traceArgToString() 0 16 6
A toText() 0 10 2
A traceToString() 0 21 3
A toHTML() 0 17 1
A tracesToString() 0 14 5
A traceArgsToString() 0 7 2
A formatFilename() 0 3 1
A isShortcutCall() 0 3 1
A displayErrors() 0 4 3
A formatExceptionAsTrace() 0 9 1
1
<?php
2
3
namespace HexMakina\Debugger
4
{
5
    class Debugger
6
    {
7
        private static $skip_classes = [__CLASS__];
8
9
        public function setSkipClasses($skip_classes)
10
        {
11
            foreach ($skip_classes as $class) {
12
                array_push(self::$skip_classes, $class);
13
            }
14
            self::$skip_classes = array_unique(self::$skip_classes);
15
        }
16
17
        // -- visual dump (display depends on env)
18
        // return the var itself, for easy code debugging
19
        public static function visualDump($var, $var_name = null, $full_backtrace = false)
20
        {
21
22
            if ($var instanceof \Throwable) {
23
                $traces = $var->getTrace();
24
                $dump = self::formatExceptionAsTrace($var);
25
            } else {
26
                $traces = debug_backtrace();
27
28
                ob_start();
29
                var_dump($var);
30
                $dump = ob_get_clean();
31
            }
32
33
            $traces = self::purgeTraces($traces);
34
            $message = self::toHTML($dump, $var_name, $traces, $full_backtrace);
35
36
            self::displayErrors($message);
37
            return $var;
38
        }
39
40
        private static function formatExceptionAsTrace($var)
41
        {
42
            return self::traceToString([
43
              'class' => get_class($var),
44
              'line' => $var->getLine(),
45
              'file' => $var->getFile(),
46
              'function' => 'getCode',
47
              'args' => [$var->getCode()]
48
            ]) . PHP_EOL . $var->getMessage();
49
        }
50
        // should we display something ?
51
        public static function displayErrors($error_message = null)
52
        {
53
            if (!empty($error_message) && ini_get('display_errors') == '1') {
54
                echo $error_message;
55
            }
56
        }
57
58
        private static function purgeTraces($traces)
59
        {
60
            $purged = [];
61
          // removes all internal calls
62
            foreach ($traces as $i => $trace) {
63
                if (empty($traces[$i]['class']) || !in_array($traces[$i]['class'], self::$skip_classes)) {
64
                    $purged[$i] = $trace;
65
                }
66
            }
67
68
            return $purged;
69
        }
70
71
        // -- formatting
72
        public static function toText($var_dump, $var_name, $backtrace, $full_backtrace)
73
        {
74
            return PHP_EOL
75
            . "******* "
76
            . (empty($var_name) ? $backtrace[1]['function'] . '()' : " ($var_name) ")
77
            . " *******"
78
            . PHP_EOL
79
            . self::tracesToString($backtrace, $full_backtrace)
80
            . PHP_EOL
81
            . $var_dump;
82
        }
83
84
        public static function toHTML($var_dump, $var_name, $backtrace, $full_backtrace)
85
        {
86
            $css = [
87
            'text-align:left',
88
            'z-index:9999',
89
            'background-color:#FFF',
90
            'color:#000',
91
            'padding:0.5em',
92
            'font-size:0.7em',
93
            'margin:0 0 1em 0',
94
            'font-family:courier'
95
            ];
96
97
            return sprintf(
98
                '<pre style="%s">%s</pre>',
99
                implode(';', $css),
100
                self::toText($var_dump, $var_name, $backtrace, $full_backtrace)
101
            );
102
        }
103
104
        // reduce_file_depth_to allows for short filepath, cause it gets crazy sometimes
105
        private static function formatFilename($file, $reduce_file_depth_to = 5)
0 ignored issues
show
Unused Code introduced by
The method formatFilename() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
106
        {
107
            return implode('/', array_slice(explode('/', $file), -$reduce_file_depth_to, $reduce_file_depth_to));
108
        }
109
110
        // -- formatting : nice backtrace
111
        private static function tracesToString($traces, $full_backtrace)
112
        {
113
            $formated_traces = [];
114
115
            foreach ($traces as $depth => $trace) {
116
                if (!empty($trace_string = self::traceToString($trace))) {
117
                    $formated_traces [] = $trace_string;
118
                }
119
                if (!empty($formated_traces) && $full_backtrace === false) {
120
                    break;
121
                }
122
            }
123
124
            return implode(PHP_EOL, array_reverse($formated_traces));
125
        }
126
127
        private static function traceToString($trace)
128
        {
129
            $function_name = $trace['function'] ?? '?';
130
            $class_name = $trace['class'] ?? '';
131
132
            if (self::isShortcutCall($function_name)) {
133
                $args = date_format(date_create(), 'ymd:his');
134
            } else {
135
                $args = self::traceArgsToString($trace['args'] ?? []);
136
            }
137
138
            $call_file = isset($trace['file']) ? basename($trace['file']) : '?';
139
            $call_line = $trace['line'] ?? '?';
140
141
            return sprintf(
142
                '[%-23.23s %3s]  %s%s(%s)',
143
                $call_file,
144
                $call_line,
145
                "$class_name::",
146
                $function_name,
147
                $args
148
            );
149
        }
150
151
        private static function traceArgsToString($trace_args)
152
        {
153
            $ret = [];
154
            foreach ($trace_args as $arg) {
155
                $ret[] = self::traceArgToString($arg);
156
            }
157
            return implode(', ', $ret);
158
        }
159
160
        private static function traceArgToString($arg)
161
        {
162
            $ret = 'unknown type';
163
164
            if (is_null($arg)) {
165
                $ret = 'NULL';
166
            } elseif (is_bool($arg)) {
167
                $ret = 'bool:' . ((int)$arg);
168
            } elseif (is_scalar($arg)) {
169
                $ret = $arg;
170
            } elseif (is_object($arg)) {
171
                $ret = get_class($arg);
172
            } elseif (is_array($arg)) {
173
                $ret = 'Array #' . count($arg);
174
            }
175
            return $ret;
176
        }
177
178
        private static function isShortcutCall($function_name): bool
179
        {
180
            return in_array($function_name, ['vd', 'dd','vdt', 'ddt']);
181
        }
182
    }
183
}
184
namespace
185
{
186
    use HexMakina\Debugger\Debugger;
187
188
    if (!function_exists('vd')) {
189
        function vd($var, $var_name = null)
190
        {
191
            Debugger::visualDump($var, $var_name, false);
192
        }
193
    }
194
    if (!function_exists('dd')) {
195
        function dd($var, $var_name = null)
196
        {
197
            Debugger::visualDump($var, $var_name, false);
198
            die;
199
        }
200
    }
201
    if (!function_exists('vdt')) {
202
        function vdt($var, $var_name = null)
203
        {
204
            Debugger::visualDump($var, $var_name, true);
205
        }
206
    }
207
    if (!function_exists('ddt')) {
208
        function ddt($var, $var_name = null)
209
        {
210
            Debugger::visualDump($var, $var_name, true);
211
            die;
212
        }
213
    }
214
}
215