Passed
Push — master ( 79149c...dd37f9 )
by Richard
05:12 queued 11s
created

Kint::dump()   F

Complexity

Conditions 40
Paths > 20000

Size

Total Lines 170
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 101
dl 0
loc 170
rs 0
c 0
b 0
f 0
cc 40
nc 215041
nop 1

How to fix   Long Method    Complexity   

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 Kint
4
{
5
    /**
6
     * @var mixed Kint mode
7
     *
8
     * false: Disabled
9
     * true: Enabled, default mode selection
10
     * string: Manual mode selection
11
     */
12
    public static $enabled_mode = true;
13
14
    /**
15
     * Default mode.
16
     *
17
     * @var string
18
     */
19
    public static $mode_default = self::MODE_RICH;
20
21
    /**
22
     * Default mode in CLI with cli_detection on.
23
     *
24
     * @var string
25
     */
26
    public static $mode_default_cli = self::MODE_CLI;
27
28
    /**
29
     * @var bool Return output instead of echoing
30
     */
31
    public static $return;
32
33
    /**
34
     * @var string format of the link to the source file in trace entries.
35
     *
36
     * Use %f for file path, %l for line number.
37
     *
38
     * [!] EXAMPLE (works with for phpStorm and RemoteCall Plugin):
39
     *
40
     * Kint::$file_link_format = 'http://localhost:8091/?message=%f:%l';
41
     */
42
    public static $file_link_format = '';
43
44
    /**
45
     * @var bool whether to display where kint was called from
46
     */
47
    public static $display_called_from = true;
48
49
    /**
50
     * @var array base directories of your application that will be displayed instead of the full path.
51
     *
52
     * Keys are paths, values are replacement strings
53
     *
54
     * [!] EXAMPLE (for Kohana framework):
55
     *
56
     * Kint::$app_root_dirs = array(
57
     *      APPPATH => 'APPPATH',
58
     *      SYSPATH => 'SYSPATH',
59
     *      MODPATH => 'MODPATH',
60
     *      DOCROOT => 'DOCROOT',
61
     * );
62
     *
63
     * [!] EXAMPLE #2 (for a semi-universal approach)
64
     *
65
     * Kint::$app_root_dirs = array(
66
     *      realpath( __DIR__ . '/../../..' ) => 'ROOT', // go up as many levels as needed
67
     * );
68
     */
69
    public static $app_root_dirs = array();
70
71
    /**
72
     * @var int max array/object levels to go deep, if zero no limits are applied
73
     */
74
    public static $max_depth = 6;
75
76
    /**
77
     * @var bool expand all trees by default for rich view
78
     */
79
    public static $expanded = false;
80
81
    /**
82
     * @var bool enable detection when Kint is command line.
83
     *
84
     * Formats output with whitespace only; does not HTML-escape it
85
     */
86
    public static $cli_detection = true;
87
88
    /**
89
     * @var array Kint aliases. Add debug functions in Kint wrappers here to fix modifiers and backtraces
90
     */
91
    public static $aliases = array(
92
        array('Kint', 'dump'),
93
        array('Kint', 'trace'),
94
        array('Kint', 'dumpArray'),
95
    );
96
97
    /**
98
     * @var array Kint_Renderer descendants. Add to array to extend.
99
     */
100
    public static $renderers = array(
101
        self::MODE_RICH => 'Kint_Renderer_Rich',
102
        self::MODE_PLAIN => 'Kint_Renderer_Plain',
103
        self::MODE_TEXT => 'Kint_Renderer_Text',
104
        self::MODE_CLI => 'Kint_Renderer_Cli',
105
    );
106
107
    const MODE_RICH = 'r';
108
    const MODE_TEXT = 't';
109
    const MODE_CLI = 'c';
110
    const MODE_PLAIN = 'p';
111
112
    public static $plugins = array(
113
        'Kint_Parser_Base64',
114
        'Kint_Parser_Blacklist',
115
        'Kint_Parser_ClassMethods',
116
        'Kint_Parser_ClassStatics',
117
        'Kint_Parser_Closure',
118
        'Kint_Parser_Color',
119
        'Kint_Parser_DateTime',
120
        'Kint_Parser_FsPath',
121
        'Kint_Parser_Iterator',
122
        'Kint_Parser_Json',
123
        'Kint_Parser_Microtime',
124
        'Kint_Parser_SimpleXMLElement',
125
        'Kint_Parser_SplFileInfo',
126
        'Kint_Parser_SplObjectStorage',
127
        'Kint_Parser_Stream',
128
        'Kint_Parser_Table',
129
        'Kint_Parser_Throwable',
130
        'Kint_Parser_Timestamp',
131
        'Kint_Parser_ToString',
132
        'Kint_Parser_Trace',
133
        'Kint_Parser_Xml',
134
    );
135
136
    private static $plugin_pool = array();
137
    private static $dump_array = false;
138
    private static $names = array();
139
140
    /**
141
     * Stashes or sets all settings at once.
142
     *
143
     * @param array|null $settings Array of all settings to be set or null to set none
144
     *
145
     * @return array Current settings
146
     */
147
    public static function settings(array $settings = null)
148
    {
149
        static $keys = array(
150
            'aliases',
151
            'app_root_dirs',
152
            'cli_detection',
153
            'display_called_from',
154
            'enabled_mode',
155
            'expanded',
156
            'file_link_format',
157
            'max_depth',
158
            'mode_default',
159
            'mode_default_cli',
160
            'renderers',
161
            'return',
162
            'plugins',
163
        );
164
165
        $out = array();
166
167
        foreach ($keys as $key) {
168
            $out[$key] = self::$$key;
169
        }
170
171
        if ($settings !== null) {
172
            $in = array_intersect_key($settings, $out);
173
            foreach ($in as $key => $val) {
174
                self::$$key = $val;
175
            }
176
        }
177
178
        return $out;
179
    }
180
181
    /**
182
     * Prints a debug backtrace, same as Kint::dump(1).
183
     *
184
     * @param array $trace [OPTIONAL] you can pass your own trace, otherwise, `debug_backtrace` will be called
185
     *
186
     * @return mixed
187
     */
188
    public static function trace($trace = null)
189
    {
190
        if ($trace === null) {
191
            if (KINT_PHP525) {
192
                $trace = debug_backtrace(true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
                $trace = debug_backtrace(/** @scrutinizer ignore-type */ true);
Loading history...
193
            } else {
194
                $trace = debug_backtrace();
195
            }
196
        } else {
197
            return self::dump($trace);
198
        }
199
200
        Kint_Parser_Trace::normalizeAliases(self::$aliases);
201
202
        $trimmed_trace = array();
203
204
        foreach ($trace as $frame) {
205
            if (Kint_Parser_Trace::frameIsListed($frame, self::$aliases)) {
206
                $trimmed_trace = array();
207
            }
208
209
            $trimmed_trace[] = $frame;
210
        }
211
212
        return self::dumpArray(
213
            array($trimmed_trace),
214
            array(Kint_Object::blank('Kint::trace()', 'debug_backtrace()'))
215
        );
216
    }
217
218
    /**
219
     * Dumps an array as separate values, and uses $names to seed the parser.
220
     *
221
     * @param array                   $data  Data to be dumped
222
     * @param array[Kint_Object]|null $names Array of Kint_Object to seed the parser with
0 ignored issues
show
Documentation Bug introduced by
The doc comment array[Kint_Object]|null at position 1 could not be parsed: Expected ']' at position 1, but found '['.
Loading history...
223
     */
224
    public static function dumpArray(array $data, array $names = null)
225
    {
226
        self::$names = $names;
227
        self::$dump_array = true;
228
229
        $out = self::dump($data);
230
231
        self::$names = null;
232
        self::$dump_array = false;
233
234
        return $out;
235
    }
236
237
    /**
238
     * Dump information about variables, accepts any number of parameters, supports modifiers:.
239
     *
240
     *  clean up any output before kint and place the dump at the top of page:
241
     *   - Kint::dump()
242
     *  *****
243
     *  expand all nodes on display:
244
     *   ! Kint::dump()
245
     *  *****
246
     *  dump variables disregarding their depth:
247
     *   + Kint::dump()
248
     *  *****
249
     *  return output instead of displaying it:
250
     *
251
     *   @ Kint::dump()
252
     *  *****
253
     *  force output as plain text
254
     *   ~ Kint::dump()
255
     *
256
     * Modifiers are supported by all dump wrapper functions, including Kint::trace(). Space is optional.
257
     *
258
     * @param mixed $data
259
     *
260
     * @return int|string
261
     */
262
    public static function dump($data = null)
263
    {
264
        if (!self::$enabled_mode) {
265
            return 0;
266
        }
267
268
        $stash = self::settings();
269
        $num_args = func_num_args();
270
271
        list($params, $modifiers, $callee, $caller, $minitrace) = self::getCalleeInfo(
272
            defined('DEBUG_BACKTRACE_IGNORE_ARGS')
273
                ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)
274
                : debug_backtrace(),
275
            $num_args
276
        );
277
278
        // set mode for current run
279
        if (self::$enabled_mode === true) {
280
            self::$enabled_mode = self::$mode_default;
281
            if (PHP_SAPI === 'cli' && self::$cli_detection === true) {
282
                self::$enabled_mode = self::$mode_default_cli;
283
            }
284
        }
285
286
        if (in_array('~', $modifiers)) {
287
            self::$enabled_mode = self::MODE_TEXT;
288
        }
289
290
        if (!array_key_exists(self::$enabled_mode, self::$renderers)) {
291
            $renderer = self::$renderers[self::MODE_PLAIN];
292
        } else {
293
            $renderer = self::$renderers[self::$enabled_mode];
294
        }
295
296
        // process modifiers: @, +, ! and -
297
        if (in_array('-', $modifiers)) {
298
            while (ob_get_level()) {
299
                ob_end_clean();
300
            }
301
        }
302
        if (in_array('!', $modifiers)) {
303
            self::$expanded = true;
304
        }
305
        if (in_array('+', $modifiers)) {
306
            self::$max_depth = false;
0 ignored issues
show
Documentation Bug introduced by
The property $max_depth was declared of type integer, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
307
        }
308
        if (in_array('@', $modifiers)) {
309
            self::$return = true;
310
        }
311
312
        $renderer = new $renderer(array(
313
            'num_args' => $num_args,
314
            'params' => $params,
315
            'modifiers' => $modifiers,
316
            'callee' => $callee,
317
            'caller' => $caller,
318
            'minitrace' => $minitrace,
319
            'settings' => self::settings(),
320
            'stash' => $stash,
321
        ));
322
323
        $plugins = array();
324
325
        foreach (self::$plugins as $plugin) {
326
            if ($plugin instanceof Kint_Parser_Plugin) {
327
                $plugins[] = $plugin;
328
            } elseif (is_string($plugin) && is_subclass_of($plugin, 'Kint_Parser_Plugin')) {
329
                if (!isset(self::$plugin_pool[$plugin])) {
330
                    $p = new $plugin();
331
                    self::$plugin_pool[$plugin] = $p;
332
                }
333
                $plugins[] = self::$plugin_pool[$plugin];
334
            }
335
        }
336
337
        $plugins = $renderer->parserPlugins($plugins);
338
339
        $output = $renderer->preRender();
340
341
        $parser = new Kint_Parser(self::$max_depth, empty($caller['class']) ? null : $caller['class']);
342
343
        foreach ($plugins as $plugin) {
344
            $parser->addPlugin($plugin);
345
        }
346
347
        // Kint::dump(1) shorthand
348
        if (!self::$dump_array && (!isset($params[0]['name']) || $params[0]['name'] == '1') && $num_args === 1 && $data === 1) {
349
            if (KINT_PHP525) {
350
                $data = debug_backtrace(true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

350
                $data = debug_backtrace(/** @scrutinizer ignore-type */ true);
Loading history...
351
            } else {
352
                $data = debug_backtrace();
353
            }
354
355
            $trace = array();
356
357
            // No need to normalize as we've already called it through getCalleeInfo at this point
358
            foreach ($data as $index => $frame) {
359
                if (Kint_Parser_Trace::frameIsListed($frame, self::$aliases)) {
360
                    $trace = array();
361
                }
362
363
                $trace[] = $frame;
364
            }
365
366
            $lastframe = reset($trace);
367
            $tracename = $lastframe['function'].'(1)';
368
            if (isset($lastframe['class'], $lastframe['type'])) {
369
                $tracename = $lastframe['class'].$lastframe['type'].$tracename;
370
            }
371
            $tracebase = Kint_Object::blank($tracename, 'debug_backtrace()');
372
373
            if (empty($trace)) {
374
                $output .= $renderer->render($tracebase->transplant(new Kint_Object_Trace()));
375
            } else {
376
                $output .= $renderer->render($parser->parse($trace, $tracebase));
377
            }
378
        } else {
379
            $data = func_get_args();
380
            if ($data === array()) {
381
                $output .= $renderer->render(new Kint_Object_Nothing());
382
            }
383
384
            if (self::$dump_array) {
385
                $data = $data[0];
386
            }
387
388
            static $blacklist = array('null', 'true', 'false', 'array(...)', 'array()', '"..."', 'b"..."', '[...]', '[]', '(...)', '()');
389
390
            foreach ($data as $i => $argument) {
391
                if (isset(self::$names[$i])) {
392
                    $output .= $renderer->render(
393
                        $parser->parse($argument, self::$names[$i])
394
                    );
395
                    continue;
396
                }
397
398
                if (!isset($params[$i]['name']) || is_numeric($params[$i]['name']) || in_array(str_replace("'", '"', strtolower($params[$i]['name'])), $blacklist, true)) {
399
                    $name = null;
400
                } else {
401
                    $name = $params[$i]['name'];
402
                }
403
404
                if (isset($params[$i]['path'])) {
405
                    $access_path = $params[$i]['path'];
406
407
                    if (!empty($params[$i]['expression'])) {
408
                        $access_path = '('.$access_path.')';
409
                    }
410
                } else {
411
                    $access_path = '$'.$i;
412
                }
413
414
                $output .= $renderer->render(
415
                    $parser->parse($argument, Kint_Object::blank($name, $access_path))
416
                );
417
            }
418
        }
419
420
        $output .= $renderer->postRender();
421
422
        if (self::$return) {
423
            self::settings($stash);
424
425
            return $output;
426
        }
427
428
        self::settings($stash);
429
        echo $output;
430
431
        return 0;
432
    }
433
434
    /**
435
     * generic path display callback, can be configured in app_root_dirs; purpose is
436
     * to show relevant path info and hide as much of the path as possible.
437
     *
438
     * @param string $file
439
     *
440
     * @return string
441
     */
442
    public static function shortenPath($file)
443
    {
444
        $file = array_values(array_filter(explode('/', str_replace('\\', '/', $file)), 'strlen'));
445
446
        $longest_match = 0;
447
        $match = '/';
448
449
        foreach (self::$app_root_dirs as $path => $alias) {
450
            if (empty($path)) {
451
                continue;
452
            }
453
454
            $path = array_values(array_filter(explode('/', str_replace('\\', '/', $path)), 'strlen'));
455
456
            if (array_slice($file, 0, count($path)) === $path && count($path) > $longest_match) {
457
                $longest_match = count($path);
458
                $match = $alias;
459
            }
460
        }
461
462
        if ($longest_match) {
463
            $file = array_merge(array($match), array_slice($file, $longest_match));
464
465
            return implode('/', $file);
466
        } else {
467
            // fallback to find common path with Kint dir
468
            $kint = array_values(array_filter(explode('/', str_replace('\\', '/', KINT_DIR)), 'strlen'));
469
470
            foreach ($file as $i => $part) {
471
                if (!isset($kint[$i]) || $kint[$i] !== $part) {
472
                    return ($i ? '.../' : '/').implode('/', array_slice($file, $i));
473
                }
474
            }
475
476
            return '/'.implode('/', $file);
477
        }
478
    }
479
480
    public static function getIdeLink($file, $line)
481
    {
482
        return str_replace(array('%f', '%l'), array($file, $line), self::$file_link_format);
483
    }
484
485
    /**
486
     * returns parameter names that the function was passed, as well as any predefined symbols before function
487
     * call (modifiers).
488
     *
489
     * @param array $trace
490
     *
491
     * @return array($params, $modifiers, $callee, $caller, $miniTrace)
492
     */
493
    private static function getCalleeInfo($trace, $num_params)
494
    {
495
        Kint_Parser_Trace::normalizeAliases(self::$aliases);
496
        $miniTrace = array();
497
498
        foreach ($trace as $index => $frame) {
499
            if (Kint_Parser_Trace::frameIsListed($frame, self::$aliases)) {
500
                $miniTrace = array();
501
            }
502
503
            if (!Kint_Parser_Trace::frameIsListed($frame, array('spl_autoload_call'))) {
504
                $miniTrace[] = $frame;
505
            }
506
        }
507
508
        $callee = reset($miniTrace);
509
        $caller = next($miniTrace);
510
        if (!$callee) {
511
            $callee = null;
512
        }
513
        if (!$caller) {
514
            $caller = null;
515
        }
516
517
        unset($miniTrace[0]);
518
519
        foreach ($miniTrace as $index => &$frame) {
520
            if (!isset($frame['file'], $frame['line'])) {
521
                unset($miniTrace[$index]);
522
            } else {
523
                unset($frame['object'], $frame['args']);
524
            }
525
        }
526
527
        $miniTrace = array_values($miniTrace);
528
529
        if (!isset($callee['file'], $callee['line']) || !is_readable($callee['file'])) {
530
            return array(null, array(), $callee, $caller, $miniTrace);
531
        }
532
533
        // open the file and read it up to the position where the function call expression ended
534
        if (empty($callee['class'])) {
535
            $callfunc = $callee['function'];
536
        } else {
537
            $callfunc = array($callee['class'], $callee['function']);
538
        }
539
540
        $calls = Kint_SourceParser::getFunctionCalls(
541
            file_get_contents($callee['file']),
542
            $callee['line'],
543
            $callfunc
544
        );
545
546
        $return = array(null, array(), $callee, $caller, $miniTrace);
547
548
        foreach ($calls as $call) {
549
            $is_unpack = false;
550
551
            // Handle argument unpacking as a last resort
552
            if (KINT_PHP56) {
553
                foreach ($call['parameters'] as $i => &$param) {
554
                    if (strpos($param['name'], '...') === 0) {
555
                        if ($i === count($call['parameters']) - 1) {
556
                            for ($j = 1; $j + $i < $num_params; ++$j) {
557
                                $call['parameters'][] = array(
558
                                    'name' => 'array_values('.substr($param['name'], 3).')['.$j.']',
559
                                    'path' => 'array_values('.substr($param['path'], 3).')['.$j.']',
560
                                    'expression' => false,
561
                                );
562
                            }
563
564
                            $param['name'] = 'reset('.substr($param['name'], 3).')';
565
                            $param['path'] = 'reset('.substr($param['path'], 3).')';
566
                            $param['expression'] = false;
567
                        } else {
568
                            $call['parameters'] = array_slice($call['parameters'], 0, $i);
569
                        }
570
571
                        $is_unpack = true;
572
                        break;
573
                    }
574
                }
575
            }
576
577
            if ($is_unpack || count($call['parameters']) === $num_params) {
578
                if ($return[0] === null) {
579
                    $return = array($call['parameters'], $call['modifiers'], $callee, $caller, $miniTrace);
580
                } else {
581
                    // If we have multiple calls on the same line with the same amount of arguments,
582
                    // we can't be sure which it is so just return null and let them figure it out
583
                    return array(null, array(), $callee, $caller, $miniTrace);
584
                }
585
            }
586
        }
587
588
        return $return;
589
    }
590
591
    public static function composerGetExtras($key = 'kint')
592
    {
593
        $extras = array();
594
595
        if (!KINT_PHP53) {
596
            return $extras;
597
        }
598
599
        $folder = KINT_DIR.'/vendor';
600
601
        for ($i = 0; $i < 4; ++$i) {
602
            $installed = $folder.'/composer/installed.json';
603
604
            if (file_exists($installed) && is_readable($installed)) {
605
                $packages = json_decode(file_get_contents($installed), true);
606
607
                foreach ($packages as $package) {
608
                    if (isset($package['extra'][$key]) && is_array($package['extra'][$key])) {
609
                        $extras = array_replace($extras, $package['extra'][$key]);
610
                    }
611
                }
612
613
                $folder = dirname($folder);
614
615
                if (file_exists($folder.'/composer.json') && is_readable($folder.'/composer.json')) {
616
                    $composer = json_decode(file_get_contents($folder.'/composer.json'), true);
617
618
                    if (isset($composer['extra'][$key]) && is_array($composer['extra'][$key])) {
619
                        $extras = array_replace($extras, $composer['extra'][$key]);
620
                    }
621
                }
622
623
                break;
624
            } else {
625
                $folder = dirname($folder);
626
            }
627
        }
628
629
        return $extras;
630
    }
631
632
    public static function composerGetDisableHelperFunctions()
633
    {
634
        $extras = self::composerGetExtras();
635
636
        return !empty($extras['disable-helper-functions']);
637
    }
638
}
639