Passed
Push — main ( 871ea4...e17d1e )
by Sammy
03:00 queued 16s
created

Debugger::tracesToString()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 7
eloc 22
c 3
b 0
f 0
nc 10
nop 2
dl 0
loc 36
rs 8.6346
1
<?php
2
3
namespace HexMakina\Debugger
4
{
5
    class Debugger
6
    {
7
        private static $meta_methods = [];
8
9
        public function __construct()
10
        {
11
            $debugger = new \ReflectionClass(__CLASS__);
12
            $methods = $debugger->getMethods();
13
            self::$meta_methods = array_map(function ($m) {
14
                return $m->name;
15
            }, $methods);
16
        }
17
18
        public static function displayErrors($error_message = null)
19
        {
20
            $should_display = ini_get('display_errors') == '1';
21
22
            if ($should_display && !empty($error_message)) {
23
                echo self::toHTML($error_message);
24
            }
25
        }
26
27
        // -- dump on variable type (Throwables, array, anything else)
28
        private static function dump($var, $var_name = null, $full_backtrace = true)
29
        {
30
            if (is_object($var) && (is_subclass_of($var, 'Error') || is_subclass_of($var, 'Exception'))) {
31
                $backtrace = $var->getTrace();
32
                $full_backtrace = true;
33
                $var_dump  = self::formatThrowable($var);
34
            } else {
35
                $backtrace = debug_backtrace();
36
37
                ob_start();
38
                var_dump($var);
39
                $var_dump = ob_get_clean();
40
            }
41
42
            return PHP_EOL
43
            . "*******"
44
            . (empty($var_name) ? '' : " ($var_name) ")
45
            . "*******"
46
            . PHP_EOL
47
            . self::tracesToString($backtrace, $full_backtrace)
48
            . PHP_EOL
49
            . $var_dump;
50
        }
51
52
        // -- visual dump (depends on env)
53
        public static function visualDump($var, $var_name = null, $full_backtrace = false)
54
        {
55
            self::displayErrors(self::dump($var, $var_name, $full_backtrace));
56
            return $var;
57
        }
58
59
        // -- visual dump and DIE
60
        public static function visualDumpAndDie($var, $var_name = null, $full_backtrace = true)
61
        {
62
            self::visualDump($var, $var_name, $full_backtrace);
63
            die;
64
        }
65
66
67
      // -- formatting
68
69
      // -- formatting : first line of \Throwable-based error
70
        public static function formatThrowable(\Throwable $err)
71
        {
72
            return PHP_EOL . sprintf(
73
                '%s (%d) in file %s:%d' . PHP_EOL . '%s',
74
                get_class($err),
75
                $err->getCode(),
76
                self::formatFilename($err->getFile()),
77
                $err->getLine(),
78
                $err->getMessage()
79
            );
80
        }
81
82
        public static function formatFilename($file, $reduce_file_depth_to = 5)
83
        {
84
            return implode('/', array_slice(explode('/', $file), -$reduce_file_depth_to, $reduce_file_depth_to));
85
        }
86
87
      // -- formatting : nice backtrace
88
        public static function tracesToString($traces, $full_backtrace)
89
        {
90
            $formated_traces = [];
91
92
            foreach ($traces as $depth => $trace) {
93
                $function_name = $trace['function'] ?? '?';
94
                $class_name = $trace['class'] ?? '';
95
96
                if (self::isInternalFunctionCall($class_name, $function_name)) {
97
                    continue;
98
                }
99
100
                if (!self::isShortcutCall($function_name) && isset($trace['args'])) {
101
                    $args = self::traceArgsToString($trace['args']);
102
                } else {
103
                    $args = microtime(true);
104
                }
105
106
                $call_file = isset($trace['file']) ? basename($trace['file']) : '?';
107
                $call_line = $trace['line'] ?? '?';
108
109
                $formated_traces [] = sprintf(
110
                    '[%-23.23s %3s]  %s%s(%s)',
111
                    $call_file,
112
                    $call_line,
113
                    "$class_name::",
114
                    $function_name,
115
                    $args
116
                );
117
118
                if ($full_backtrace === false) {
119
                    break;
120
                }
121
            }
122
123
            return implode(PHP_EOL, array_reverse($formated_traces));
124
        }
125
126
        private static function traceArgsToString($trace_args)
127
        {
128
            $ret = [];
129
            foreach ($trace_args as $arg) {
130
                $ret[] = self::traceArgToString($arg);
131
            }
132
            return implode(', ', $ret);
133
        }
134
135
        private static function traceArgToString($arg)
136
        {
137
            $ret = 'unknown type';
138
139
            if (is_null($arg)) {
140
                $ret = 'NULL';
141
            } elseif (is_bool($arg)) {
142
                $ret = 'bool:' . ((int)$arg);
143
            } elseif (is_scalar($arg)) {
144
                $ret = $arg;
145
            } elseif (is_object($arg)) {
146
                $ret = get_class($arg);
147
            } elseif (is_array($arg)) {
148
                $ret = 'Array #' . count($arg);
149
            }
150
            return $ret;
151
        }
152
153
        private static function isInternalFunctionCall($class_name, $function_name): bool
154
        {
155
            return $class_name === __CLASS__ && in_array($function_name, self::$meta_methods);
156
        }
157
158
        private static function isShortcutCall($function_name): bool
159
        {
160
            return in_array($function_name, ['vd', 'dd','vdt', 'ddt']);
161
        }
162
163
        private static function toHTML($message)
164
        {
165
            $css = [
166
            'text-align:left',
167
            'z-index:9999',
168
            'background-color:#FFF',
169
            'color:#000',
170
            'padding:0.5em',
171
            'font-size:0.7em',
172
            'margin:0 0 1em 0',
173
            'font-family:courier'
174
            ];
175
176
            return sprintf('<pre style="%s">%s</pre>', implode(';', $css), $message);
177
        }
178
    }
179
}
180
namespace
181
{
182
    use \HexMakina\Debugger\Debugger;
183
184
    if (!function_exists('vd')) {
185
        function vd($var, $var_name = null)
186
        {
187
            Debugger::visualDump($var, $var_name, false);
188
        }
189
    }
190
    if (!function_exists('dd')) {
191
        function dd($var, $var_name = null)
192
        {
193
            Debugger::visualDumpAndDie($var, $var_name, false);
194
        }
195
    }
196
    if (!function_exists('vdt')) {
197
        function vdt($var, $var_name = null)
198
        {
199
            Debugger::visualDump($var, $var_name, true);
200
        }
201
    }
202
    if (!function_exists('ddt')) {
203
        function ddt($var, $var_name = null)
204
        {
205
            Debugger::visualDumpAndDie($var, $var_name, true);
206
        }
207
    }
208
}
209