Passed
Push — main ( 7c5a9a...8485e0 )
by Sammy
02:09
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) {
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
                $args = self::traceArgsToString($trace['args'] ?? []);
101
                // if (!self::isShortcutCall($function_name) && isset($trace['args'])) {
102
                //
103
                // } else {
104
                //     $args = microtime(true);
105
                // }
106
107
                $call_file = isset($trace['file']) ? basename($trace['file']) : '?';
108
                $call_line = $trace['line'] ?? '?';
109
110
                $formated_traces [] = sprintf(
111
                    '[%-23.23s %3s]  %s%s(%s)',
112
                    $call_file,
113
                    $call_line,
114
                    "$class_name::",
115
                    $function_name,
116
                    $args
117
                );
118
119
                if ($full_backtrace === false) {
120
                    break;
121
                }
122
            }
123
124
            return implode(PHP_EOL, array_reverse($formated_traces));
125
        }
126
127
        private static function traceArgsToString($trace_args)
128
        {
129
            $ret = [];
130
            foreach ($trace_args as $arg) {
131
                if (is_null($arg)) {
132
                    $ret[] = 'NULL';
133
                } elseif (is_bool($arg)) {
134
                    $ret[] = 'bool:' . ((int)$arg);
135
                } elseif (is_scalar($arg)) {
136
                    $ret[] = $arg;
137
                } elseif (is_object($arg)) {
138
                    $ret[] = get_class($arg);
139
                } elseif (is_array($arg)) {
140
                    $ret[] = 'Array #' . count($arg);
141
                } else {
142
                    $ret[] = 'unknown type';
143
                }
144
            }
145
            $ret = implode(', ', $ret);
146
            return $ret;
147
        }
148
149
        private static function isInternalFunctionCall($class_name, $function_name): bool
150
        {
151
            return $class_name === __CLASS__ && in_array($function_name, self::$meta_methods);
152
        }
153
154
        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...
155
        {
156
            return in_array($function_name, ['vd', 'dd','vdt', 'ddt']);
157
        }
158
159
        private static function toHTML($message)
160
        {
161
            $css = [
162
            'text-align:left',
163
            'z-index:9999',
164
            'background-color:#FFF',
165
            'color:#000',
166
            'padding:0.5em',
167
            'font-size:0.7em',
168
            'margin:0 0 1em 0',
169
            'font-family:courier'
170
            ];
171
172
            return sprintf('<pre style="%s">%s</pre>', implode(';', $css), $message);
173
        }
174
    }
175
}
176
namespace
177
{
178
    if (!function_exists('vd')) {
179
        function vd($var, $var_name = null)
180
        {
181
            \HexMakina\Debugger\Debugger::visualDump($var, $var_name, false);
182
        }
183
    }
184
    if (!function_exists('dd')) {
185
        function dd($var, $var_name = null)
186
        {
187
            \HexMakina\Debugger\Debugger::visualDumpAndDie($var, $var_name, false);
188
        }
189
    }
190
    if (!function_exists('vdt')) {
191
        function vdt($var, $var_name = null)
192
        {
193
            \HexMakina\Debugger\Debugger::visualDump($var, $var_name, true);
194
        }
195
    }
196
    if (!function_exists('ddt')) {
197
        function ddt($var, $var_name = null)
198
        {
199
            \HexMakina\Debugger\Debugger::visualDumpAndDie($var, $var_name, true);
200
        }
201
    }
202
}
203