GetClassProperties::collectAfterKeyword()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.3946
c 0
b 0
f 0
cc 7
nc 6
nop 5
1
<?php
2
3
namespace Imanghafoori\LaravelMicroscope\Analyzers;
4
5
class GetClassProperties
6
{
7
    public static function fromFilePath($filePath)
8
    {
9
        $fp = fopen($filePath, 'r');
10
        $buffer = fread($fp, config('microscope.class_search_buffer', 2500));
11
        // In order to ensure doc blocks are closed if there is any opening we add "/**/"
12
        $tokens = token_get_all($buffer.'/**/');
13
14
        if (strpos($buffer, '{') === false) {
15
            return [null, null, null, null];
16
        }
17
18
        return self::readClassDefinition($tokens);
19
    }
20
21
    public static function readClassDefinition($tokens)
22
    {
23
        $type = $class = null;
24
        $allTokensCount = \count($tokens);
25
        $parent = null;
26
        $interfaces = $namespace = '';
27
28
        for ($i = 1; $i < $allTokensCount; $i++) {
29
            if (! $namespace) {
30
                [$i, $namespace,] = self::collectAfterKeyword($tokens, $i, T_NAMESPACE);
31
            }
32
33
            // if we reach a double colon before a class keyword
34
            // it means that, it is not a psr-4 class.
35
            if (! $class && $tokens[$i][0] == T_DOUBLE_COLON) {
36
                return [$namespace, null, null, null, null];
37
            }
38
39
            // when we reach the first "class", or "interface" or "trait" keyword
40
            if (! $class && \in_array($tokens[$i][0], [T_CLASS, T_INTERFACE, T_TRAIT])) {
41
                $class = $tokens[$i + 2][1];
42
                $type = $tokens[$i][0];
43
                $i = $i + 2;
44
                continue;
45
            }
46
47
            if (! $parent) {
48
                [$i, $parent] = self::collectAfterKeyword($tokens, $i, T_EXTENDS, [T_IMPLEMENTS], ',');
49
            }
50
51
            if (! $interfaces) {
52
                [$i, $interfaces] = self::collectAfterKeyword($tokens, $i, T_IMPLEMENTS, [], ',');
53
            }
54
        }
55
56
        if ($class == 'extends') {
57
            $class = null;
58
        }
59
60
        return [
61
            \ltrim($namespace, '\\'),
62
            $class,
63
            $type,
64
            $parent,
65
            $interfaces,
66
        ];
67
    }
68
69
    /**
70
     * @param $tokens
71
     * @param  int  $i
72
     * @param  int  $target
73
     * @param  array  $terminators
74
     * @param  string|null  $separator
75
     *
76
     * @return array
77
     */
78
    protected static function collectAfterKeyword($tokens, $i, $target, $terminators = [], $separator = null)
79
    {
80
        $terminators[] = ';';
81
        $terminators[] = '{';
82
83
        $results = '';
84
        if ($tokens[$i][0] !== $target) {
85
            return [$i, $results];
86
        }
87
88
        while (true) {
89
            $i++;
90
            // ignore white spaces
91
            if ($tokens[$i][0] === T_WHITESPACE) {
92
                continue;
93
            }
94
95
            if (($tokens[$i][0] == $separator)) {
96
                $results .= '|';
97
                $i++;
98
                continue;
99
            }
100
101
            if (\in_array($tokens[$i][0], $terminators) || ! isset($tokens[$i])) {
102
                // we go ahead and collect until we reach:
103
                // 1. an opening curly brace {
104
                // 2. or a semi-colon ;
105
                // 3. end of tokens.
106
107
                return [$i, $results];
108
            }
109
110
            $results .= $tokens[$i][1];
111
        }
112
113
        return [$i, $results];
114
    }
115
}
116