Passed
Branch main (30c07b)
by Sammy
11:03 queued 08:10
created

Debugger.php (1 issue)

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