Passed
Push — main ( e461b7...c6a0ef )
by Dmitriy
02:09
created

StacktraceParser   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 9
eloc 50
c 2
b 0
f 0
dl 0
loc 79
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A runRegexp() 0 8 2
A mapResult() 0 16 3
A filterMatches() 0 5 2
A parse() 0 3 1
A parseRegexp() 0 36 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Xepozz\StacktraceParser;
5
6
use RuntimeException;
7
8
class StacktraceParser
9
{
10
    public function parse(string $source): iterable
11
    {
12
        return $this->parseRegexp($source);
13
    }
14
15
    private function parseRegexp(string $source): iterable
16
    {
17
        $pattern = <<<REGEXP
18
        /
19
        (?:\#\d\s{main}[^$]*)
20
        |
21
        (?:
22
            (?:
23
                \#\d+\s+
24
                (
25
                    (?:\[internal\sfunction\])
26
                    |
27
                    (?<FILE>.+?)
28
                    \(
29
                        (?<LINE>\d+)
30
                    \)
31
                )
32
                :\s+
33
                (?:
34
                    (?<CLASS>[\w\\\]+)
35
                    (?<TYPE>::|->)
36
                )?
37
                (?<FUNCTION>[\w_]+)
38
                \(.*?\)\n
39
            )
40
        )
41
        /x
42
        REGEXP;
43
44
45
        $matches = [];
46
47
        $matches = $this->runRegexp($pattern, $source, $matches);
48
        $matches = $this->filterMatches($matches);
49
50
        return $this->mapResult($matches);
51
    }
52
53
    protected function filterMatches($matches): array
54
    {
55
        return array_filter(
56
            $matches,
57
            static fn(array $match) => $match['FUNCTION'] !== null || $match['LINE'] !== null
58
        );
59
    }
60
61
    protected function mapResult(array $matches): array
62
    {
63
        return array_map(static function ($match) {
64
            $result = [
65
                'class' => (string)$match['CLASS'],
66
                'type' => $match['TYPE'],
67
                'function' => $match['FUNCTION'],
68
            ];
69
            if ($match['FILE'] !== null) {
70
                $result['file'] = $match['FILE'];
71
            }
72
            if ($match['LINE'] !== null) {
73
                $result['line'] = (int)$match['LINE'];
74
            }
75
            return $result;
76
        }, $matches);
77
    }
78
79
    protected function runRegexp(string $pattern, string $source, array &$matches): array
80
    {
81
        if (!preg_match_all($pattern, $source, $matches, PREG_SET_ORDER | PREG_UNMATCHED_AS_NULL)) {
82
            throw new RuntimeException(
83
                'Parse error'
84
            );
85
        }
86
        return $matches;
87
    }
88
}