Passed
Push — main ( 7c5a9a...8485e0 )
by Sammy
02:09
created

Debugger::traceArgsToString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 3
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
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
                $ret[] = $this->traceArgToString($arg);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using $this inside a static method is generally not recommended and can lead to errors in newer PHP versions.
Loading history...
132
            }
133
            return implode(', ', $ret);
134
        }
135
136
        private static function traceArgToString($arg)
137
        {
138
            $ret = 'unknown type';
139
140
            if (is_null($arg)) {
141
                $ret = 'NULL';
142
            } elseif (is_bool($arg)) {
143
                $ret = 'bool:' . ((int)$arg);
144
            } elseif (is_scalar($arg)) {
145
                $ret = $arg;
146
            } elseif (is_object($arg)) {
147
                $ret = get_class($arg);
148
            } elseif (is_array($arg)) {
149
                $ret = 'Array #' . count($arg);
150
            }
151
            return $ret;
152
        }
153
154
        private static function isInternalFunctionCall($class_name, $function_name): bool
155
        {
156
            return $class_name === __CLASS__ && in_array($function_name, self::$meta_methods);
157
        }
158
159
        // private static function isShortcutCall($function_name): bool
160
        // {
161
        //     return in_array($function_name, ['vd', 'dd','vdt', 'ddt']);
162
        // }
163
164
        private static function toHTML($message)
165
        {
166
            $css = [
167
            'text-align:left',
168
            'z-index:9999',
169
            'background-color:#FFF',
170
            'color:#000',
171
            'padding:0.5em',
172
            'font-size:0.7em',
173
            'margin:0 0 1em 0',
174
            'font-family:courier'
175
            ];
176
177
            return sprintf('<pre style="%s">%s</pre>', implode(';', $css), $message);
178
        }
179
    }
180
}
181
namespace
182
{
183
    if (!function_exists('vd')) {
184
        function vd($var, $var_name = null)
185
        {
186
            \HexMakina\Debugger\Debugger::visualDump($var, $var_name, false);
187
        }
188
    }
189
    if (!function_exists('dd')) {
190
        function dd($var, $var_name = null)
191
        {
192
            \HexMakina\Debugger\Debugger::visualDumpAndDie($var, $var_name, false);
193
        }
194
    }
195
    if (!function_exists('vdt')) {
196
        function vdt($var, $var_name = null)
197
        {
198
            \HexMakina\Debugger\Debugger::visualDump($var, $var_name, true);
199
        }
200
    }
201
    if (!function_exists('ddt')) {
202
        function ddt($var, $var_name = null)
203
        {
204
            \HexMakina\Debugger\Debugger::visualDumpAndDie($var, $var_name, true);
205
        }
206
    }
207
}
208