Completed
Push — master ( 401e95...bad090 )
by Steevan
27:41
created

DumpBacktrace::dumpBacktraces()   C

Complexity

Conditions 8
Paths 17

Size

Total Lines 76
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 76
rs 6.1941
cc 8
eloc 32
nc 17
nop 1

2 Methods

Rating   Name   Duplication   Size   Complexity  
B DumpBacktrace::getBacktracesDump() 0 26 2
B DumpBacktrace::getStylesDump() 0 33 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
class DumpBacktrace
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
4
{
5
    /** @var bool|string */
6
    protected static $removePathPrefix = true;
7
8
    /**
9
     * @param bool|string $remove
10
     */
11
    public static function setRemovePathPrefix($remove)
12
    {
13
        static::$removePathPrefix = $remove;
14
    }
15
16
    /**
17
     * @param int $offset
18
     * @param int|null $limit
19
     */
20
    public static function dump($offset = 0, $limit = null)
21
    {
22
        echo static::getBacktracesDump(static::getBacktraces($offset + 1, $limit));
23
    }
24
25
    /**
26
     * @param int $offset
27
     * @param int|null $limit
28
     * @return array
29
     */
30
    public static function getBacktraces($offset = 0, $limit = null)
31
    {
32
        if ($limit !== null) {
33
            $limit += $offset;
34
        }
35
36
        $filteredBacktraces = [];
37
        foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $limit) as $dumpIndex => $backtrace) {
38
            if ($dumpIndex > $offset) {
39
                $filteredBacktrace = [
40
                    'file' => isset($backtrace['file']) ? $backtrace['file'] : null,
41
                    'line' => isset($backtrace['line']) ? $backtrace['line'] : null,
42
                ];
43
                if (isset($backtrace['class'])) {
44
                    $filteredBacktrace['call'] =
45
                        $backtrace['class'] . $backtrace['type'] . $backtrace['function'] . '()';
46
                } else {
47
                    $filteredBacktrace['call'] = '(Unknow call)';
48
                }
49
50
                $filteredBacktraces[] = $filteredBacktrace;
51
            }
52
        }
53
54
        return $filteredBacktraces;
55
    }
56
57
    /**
58
     * @return array|null
59
     */
60
    protected static function getCaller()
61
    {
62
        $backtraces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 7);
63
        $nextIsCaller = false;
64
        $caller = null;
65
        foreach ($backtraces as $backtrace) {
66
            if (
67
                isset($backtrace['file'])
68
                && strpos($backtrace['file'], __FILE__) !== false
69
            ) {
70
                $nextIsCaller = true;
71
            } elseif (
72
                $nextIsCaller
73
                && (
74
                    (isset($backtrace['file']) && strpos($backtrace['file'], __FILE__) === false)
75
                    || isset($backtrace['file']) === false
76
                )
77
            ) {
78
                $caller = $backtrace;
79
                break;
80
            }
81
        }
82
        if ($nextIsCaller === false && count($backtraces) > 0) {
83
            $caller = $backtraces[0];
84
        }
85
86
        return $caller;
87
    }
88
89
    /**
90
     * @param array $backtraces
91
     * @return string
92
     */
93
    protected static function getBacktracesDump(array $backtraces)
94
    {
95
        $return = static::getStylesDump();
96
        $return .= static::getJavascriptDump();
97
98
        $return .= '<div class="steevanb-backtrace-container">';
99
        $return .= static::getCallerDump();
100
101
        $return .= '
102
            <table class="table-backtrace">
103
                <tr>
104
                    <th>#</th>
105
                    <th>File::Line</th>
106
                    <th>Call</th>
107
                </tr>
108
        ';
109
        $previewPrefix = uniqid('steevanb_backtrace_preview');
110
        foreach ($backtraces as $index => $backtrace) {
111
            $return .= static::getBacktraceDump($backtrace, $index, $previewPrefix);
112
        }
113
        $return .= '</table>';
114
115
        $return .= '</div>';
116
117
        return $return;
118
    }
119
120
    /**
121
     * @return string
122
     */
123
    protected static function getStylesDump()
124
    {
125
        return '
126
            <style type="text/css">
127
                .steevanb-backtrace-container {
128
                    padding: 5px;
129
                    border: solid 2px #9e9e9e;
130
                    background-color: #F5F5F5;
131
                    cursor: default;
132
                    font-family: monospace;
133
                }
134
                .steevanb-backtrace-container table {
135
                    border-collapse: collapse;
136
                }
137
                .steevanb-backtrace-container table.table-backtrace tr.dark {
138
                    background-color: #e5e5e5;
139
                }
140
                .steevanb-backtrace-container table.table-backtrace td {
141
                    padding: 2px !important;
142
                }
143
                .steevanb-backtrace-container table.table-backtrace td a,
144
                .steevanb-backtrace-container table.table-backtrace td a:hover,
145
                .steevanb-backtrace-container table.table-backtrace td a:visited
146
                {
147
                    color: #4e7ca9 !important;
148
                    text-decoration: none !important;
149
                    cursor: pointer !important;
150
                }
151
                .steevanb-backtrace-container table.table-backtrace td a:hover {
152
                    text-decoration: underline !important;
153
                }
154
            </style>';
155
    }
156
157
    /**
158
     * @return string
159
     */
160
    protected static function getJavascriptDump()
161
    {
162
        return '
163
            <script type="text/javascript">
164
                function steevanb_dev_showCodePreview(id)
165
                {
166
                    var element = document.getElementById(id);
167
                    element.style.display = (element.style.display === "none") ? "" : "none";
168
                }
169
            </script>';
170
    }
171
172
    /**
173
     * @param array $backtrace
174
     * @param int $index
175
     * @param string $previewPrefix
176
     * @return string
177
     */
178
    protected static function getBacktraceDump(array $backtrace, $index, $previewPrefix)
179
    {
180
        if (isset($backtrace['file'])) {
181
            $file = basename($backtrace['file']);
182
            $filePath = $backtrace['file'];
183
            $fileFound = true;
184
        } else {
185
            $file = '(Unknow file)';
186
            $filePath = null;
187
            $fileFound = false;
188
        }
189
190
        if (isset($backtrace['line'])) {
191
            $line = $backtrace['line'];
192
            $lineFound = true;
193
        } else {
194
            $line = '(Unknow line)';
195
            $lineFound = false;
196
        }
197
198
        $codePreview = ($fileFound && $lineFound) ? static::getCodePreview($filePath, $line) : 'No preview available';
199
        $previewId = $previewPrefix . '_' . $index;
200
201
        return '
202
                <tr' . ($index % 2 ? null : ' class="dark"') . '>
203
                    <td>' . $index . '</td>
204
                    <td>
205
                        <a title="' . static::getFilePath($filePath) . '" onclick="steevanb_dev_showCodePreview(\'' . $previewId . '\')">
206
                            ' . $file . '::' . $line . '
207
                        </a>
208
                    </td>
209
                    <td>' . $backtrace['call'] . '</td>
210
                </tr>
211
                <tr' . ($index % 2 ? null : ' class="dark"') . ' id="' . $previewId . '" style="display: none">
212
                    <td colspan="3"><pre>' . $codePreview . '</pre></td>
213
                </tr>';
214
    }
215
216
    /**
217
     * @return string
218
     */
219
    protected static function getCallerDump()
220
    {
221
        $caller = static::getCaller();
222
223
        $return = '<div style="padding: 5px; background-color: #78a1c9; color: white; font-weight: bold">';
224
        $header = null;
225
        if (is_array($caller)) {
226
            $header .= isset($caller['file']) ? static::getFilePath($caller['file']) : '(Unknow file)';
227
            $header .= isset($caller['line']) ? '::' . $caller['line'] : '::(Unknow line)';
228
        } else {
229
            $header= 'Unkonw caller';
230
        }
231
        $return .= $header;
232
        $return .= '</div>';
233
234
        return $return;
235
    }
236
237
    /**
238
     * @param string $code
239
     * @return string
240
     */
241
    protected static function highlightCode($code)
242
    {
243
        $highlight = highlight_string('<?php ' . $code, true);
244
        $highlight = str_replace('>&lt;?php&nbsp;', null, $highlight);
245
246
        return $highlight;
247
    }
248
249
    /**
250
     * @param string $file
251
     * @param int $line
252
     * @return string
253
     */
254
    protected static function getCodePreview($file, $line)
255
    {
256
        $preview = [];
257
        $lineMin = $line - 6;
258
        $lineMax = $line + 4;
259
        foreach (file($file) as $index => $codeLine) {
260
            if ($index >= $lineMin && $index <= $lineMax) {
261
                if ($index === $line - 1) {
262
                    $preview[] = '<span style="background-color: #7fd189">' . rtrim($codeLine) . '</span>';
263
                } else {
264
                    $preview[] = rtrim($codeLine);
265
                }
266
            } elseif ($index > $lineMax) {
267
                break;
268
            }
269
        }
270
271
        return implode('<br />', $preview);
272
    }
273
274
    /**
275
     * @param string $path
276
     * @return string
277
     */
278
    protected static function getFilePath($path)
279
    {
280
        $path = realpath($path);
281
282
        if (static::$removePathPrefix === false) {
283
            $return = $path;
284
        } else {
285
            // assume that we are in vendor/ dir
286
            $prefix = (static::$removePathPrefix === true) ? realpath(__DIR__ . '/../../../../../') : static::$removePathPrefix;
287
            $return = (substr($path, 0, strlen($prefix)) === $prefix) ? substr($path, strlen($prefix) + 1) : $path;
288
        }
289
290
        return $return;
291
    }
292
}
293