Passed
Push — main ( 89bb37...f9148d )
by Sammy
06:52
created

Debugger::purgeTraces()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 4
eloc 5
c 2
b 1
f 0
nc 3
nop 1
dl 0
loc 11
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
A Debugger::displayErrors() 0 9 3
1
<?php
2
3
namespace HexMakina\Debugger
4
{
5
    class Debugger
6
    {
7
        private static array $skip_classes = [__CLASS__];
8
9
        public function setSkipClasses($skip_classes): void
10
        {
11
            foreach ($skip_classes as $skip_class) {
12
                self::$skip_classes[] = $skip_class;
13
            }
14
15
            self::$skip_classes = array_unique(self::$skip_classes);
16
        }
17
18
        // -- visual dump (display depends on env)
19
        // return the var itself, for easy code debugging
20
        public static function visualDump($var, $var_name = null, $full_backtrace = false)
21
        {
22
23
            if ($var instanceof \Throwable) {
24
                $traces = $var->getTrace();
25
                $dump = self::formatExceptionAsTrace($var);
26
            } else {
27
                $traces = debug_backtrace();
28
29
                ob_start();
30
                var_dump($var);
31
                $dump = ob_get_clean();
32
            }
33
34
            // purge traces
35
            $traces = array_filter(
36
                $traces,
37
                static fn($trace): bool
38
                => empty($trace['class']) || !in_array($trace['class'], self::$skip_classes)
39
            );
40
41
            $message = self::toHTML($dump, $var_name, $traces, $full_backtrace);
42
43
            self::displayErrors($message);
44
            return $var;
45
        }
46
47
        private static function formatExceptionAsTrace($var): string
48
        {
49
            return self::traceToString([
50
              'class' => get_class($var),
51
              'line' => $var->getLine(),
52
              'file' => $var->getFile(),
53
              'function' => 'getCode',
54
              'args' => [$var->getCode()]
55
            ]) . PHP_EOL . $var->getMessage();
56
        }
57
58
        // should we display something ?
59
        public static function displayErrors($error_message = null): void
60
        {
61
            if (empty($error_message)) {
62
                return;
63
            }
64
            if (ini_get('display_errors') != '1') {
65
                return;
66
            }
67
            echo $error_message;
68
        }
69
70
        // -- formatting
71
        public static function toText($var_dump, $var_name, $backtrace, $full_backtrace): string
72
        {
73
            return PHP_EOL
74
            . "******* "
75
            . (empty($var_name) ? $backtrace[1]['function'] . '()' : sprintf(' (%s) ', $var_name))
76
            . " *******"
77
            . PHP_EOL
78
            . self::tracesToString($backtrace, $full_backtrace)
79
            . PHP_EOL
80
            . $var_dump;
81
        }
82
83
        public static function toHTML($var_dump, $var_name, $backtrace, $full_backtrace): string
84
        {
85
            $css = [
86
            'text-align:left',
87
            'z-index:9999',
88
            'background-color:#FFF',
89
            'color:#000',
90
            'padding:0.5em',
91
            'font-size:0.7em',
92
            'margin:0 0 1em 0',
93
            'font-family:courier'
94
            ];
95
96
            return sprintf(
97
                '<pre style="%s">%s</pre>',
98
                implode(';', $css),
99
                self::toText($var_dump, $var_name, $backtrace, $full_backtrace)
100
            );
101
        }
102
103
        // reduce_file_depth_to allows for short filepath, cause it gets crazy sometimes
104
        private static function formatFilename($file, $reduce_file_depth_to = 5): string
105
        {
106
            return implode('/', array_slice(explode('/', $file), -$reduce_file_depth_to, $reduce_file_depth_to));
107
        }
108
109
        // -- formatting : nice backtrace
110
        private static function tracesToString($traces, $full_backtrace): string
111
        {
112
            $formated_traces = [];
113
114
            foreach ($traces as $trace) {
115
                $formated_traces [] = self::traceToString($trace);
116
                if ($full_backtrace === false) {
117
                    break;
118
                }
119
            }
120
121
            return implode(PHP_EOL, array_reverse($formated_traces));
122
        }
123
124
        private static function traceToString($trace): string
125
        {
126
            $function_name = $trace['function'] ?? '?';
127
            $class_name = $trace['class'] ?? '';
128
129
            if (self::isShortcutCall($function_name)) {
130
                $args = date_format(date_create(), 'ymd:his');
131
            } else {
132
                $args = self::traceArgsToString($trace['args'] ?? []);
133
            }
134
135
            $call_file = isset($trace['file']) ? self::formatFilename($trace['file'], 2) : '?';
136
            $call_line = $trace['line'] ?? '?';
137
138
            return sprintf(
139
                '[%-33.33s %3s]  %s%s(%s)',
140
                $call_file,
141
                $call_line,
142
                sprintf('%s::', $class_name),
143
                $function_name,
144
                $args
145
            );
146
        }
147
148
        private static function traceArgsToString($trace_args): string
149
        {
150
            $ret = [];
151
            foreach ($trace_args as $trace_arg) {
152
                $ret[] = self::traceArgToString($trace_arg);
153
            }
154
155
            return implode(', ', $ret);
156
        }
157
158
        private static function traceArgToString($arg)
159
        {
160
            $ret = 'unknown type';
161
162
            if (is_null($arg)) {
163
                $ret = 'NULL';
164
            } elseif (is_bool($arg)) {
165
                $ret = 'bool:' . ((int)$arg);
166
            } elseif (is_scalar($arg)) {
167
                $ret = $arg;
168
            } elseif (is_object($arg)) {
169
                $ret = get_class($arg);
170
            } elseif (is_array($arg)) {
171
                $ret = 'Array #' . count($arg);
172
            }
173
174
            return $ret;
175
        }
176
177
        private static function isShortcutCall($function_name): bool
178
        {
179
            return in_array($function_name, ['vd', 'dd','vdt', 'ddt']);
180
        }
181
    }
182
}
183
namespace
184
{
185
    use HexMakina\Debugger\Debugger;
186
187
    if (!function_exists('vd')) {
188
        function vd($var, $var_name = null): void
189
        {
190
            Debugger::visualDump($var, $var_name, false);
191
        }
192
    }
193
194
    if (!function_exists('dd')) {
195
        function dd($var, $var_name = null): void
196
        {
197
            Debugger::visualDump($var, $var_name, false);
198
            die;
199
        }
200
    }
201
202
    if (!function_exists('vdt')) {
203
        function vdt($var, $var_name = null): void
204
        {
205
            Debugger::visualDump($var, $var_name, true);
206
        }
207
    }
208
209
    if (!function_exists('ddt')) {
210
        function ddt($var, $var_name = null): void
211
        {
212
            Debugger::visualDump($var, $var_name, true);
213
            die;
214
        }
215
    }
216
}
217