TokenizerDetector   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 134
rs 10
c 0
b 0
f 0
wmc 29

6 Methods

Rating   Name   Duplication   Size   Complexity  
A resolveClassName() 0 7 2
B processFile() 0 28 8
A isClassDeclaration() 0 7 3
A getNamespaceName() 0 14 5
A getPreviousNonWhitespaceTokenPos() 0 13 5
A getClassName() 0 19 6
1
<?php
2
/**
3
 * Created by solly [19.10.17 1:27]
4
 */
5
6
namespace insolita\codestat\lib\classdetect;
7
8
use insolita\codestat\lib\contracts\ClassDetectorInterface;
9
10
/**
11
 * The Realization honestly copy-pasted
12
 * from \SebastianBergmann\PHPLOC\Analyser::preProcessFile()
13
 */
14
class TokenizerDetector implements ClassDetectorInterface
15
{
16
    public function resolveClassName($filePath)
17
    {
18
        $className = $this->processFile($filePath);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $className is correct as $this->processFile($filePath) targeting insolita\codestat\lib\cl...Detector::processFile() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
19
        if (\is_null($className)) {
0 ignored issues
show
introduced by
The condition is_null($className) is always true.
Loading history...
20
            return null;
21
        } else {
22
            return $className;
23
        }
24
    }
25
    
26
    /**
27
     * @param array $tokens
28
     * @param int   $i
29
     *
30
     * @return string|false
31
     */
32
    protected function getNamespaceName(array $tokens, $i)
33
    {
34
        if (isset($tokens[$i + 2][1])) {
35
            $namespace = $tokens[$i + 2][1];
36
            for ($j = $i + 3; ; $j += 2) {
37
                if (isset($tokens[$j]) && $tokens[$j][0] == T_NS_SEPARATOR) {
38
                    $namespace .= '\\' . $tokens[$j + 1][1];
39
                } else {
40
                    break;
41
                }
42
            }
43
            return $namespace;
44
        }
45
        return false;
46
    }
47
    
48
    /**
49
     * @param string|false $namespace
50
     * @param array  $tokens
51
     * @param int    $i
52
     *
53
     * @return string
54
     */
55
    protected function getClassName($namespace, array $tokens, $i)
56
    {
57
        $i += 2;
58
        if (!isset($tokens[$i][1])) {
59
            return 'invalid class name';
60
        }
61
        $className = $tokens[$i][1];
62
        
63
        $namespaced = $className === '\\';
64
        
65
        while (is_array($tokens[$i + 1]) && $tokens[$i + 1][0] !== T_WHITESPACE) {
66
            $className .= $tokens[++$i][1];
67
        }
68
        
69
        if (!$namespaced && $namespace !== false) {
70
            $className = $namespace . '\\' . $className;
71
        }
72
        
73
        return $className;
74
    }
75
    
76
    /**
77
     * Extract namespace and class from file
78
     *
79
     * @param string $filename
80
     * Return FQN className
81
     *
82
     * @return string|null
83
     */
84
    protected function processFile($filename)
85
    {
86
        $tokens = token_get_all(file_get_contents($filename));
87
        $numTokens = count($tokens);
88
        $namespace = null;
89
        $className = null;
90
        
91
        for ($i = 0; $i < $numTokens; $i++) {
92
            if (is_string($tokens[$i])) {
93
                continue;
94
            }
95
            
96
            switch ($tokens[$i][0]) {
97
                case T_NAMESPACE:
98
                    $namespace = $this->getNamespaceName($tokens, $i);
99
                    break;
100
                
101
                case T_CLASS:
102
                case T_TRAIT:
103
                case T_INTERFACE:
104
                    if (!$this->isClassDeclaration($tokens, $i)) {
105
                        break;
106
                    }
107
                    $className = $this->getClassName($namespace, $tokens, $i);
108
                    break;
109
            }
110
        }
111
        return $className;
112
    }
113
    
114
    /**
115
     * @param array $tokens
116
     * @param int   $start
117
     *
118
     * @return bool
119
     */
120
    private function getPreviousNonWhitespaceTokenPos(array $tokens, $start)
121
    {
122
        if (isset($tokens[$start - 1])) {
123
            if (isset($tokens[$start - 1][0])
124
                && $tokens[$start - 1][0] == T_WHITESPACE
125
                && isset($tokens[$start - 2])) {
126
                return $start - 2;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $start - 2 returns the type integer which is incompatible with the documented return type boolean.
Loading history...
127
            } else {
128
                return $start - 1;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $start - 1 returns the type integer which is incompatible with the documented return type boolean.
Loading history...
129
            }
130
        }
131
        
132
        return false;
133
    }
134
    
135
    /**
136
     * @param array $tokens
137
     * @param int   $i
138
     *
139
     * @return bool
140
     */
141
    private function isClassDeclaration(array $tokens, $i)
142
    {
143
        $n = $this->getPreviousNonWhitespaceTokenPos($tokens, $i);
144
        
145
        return !isset($tokens[$n])
146
            || !is_array($tokens[$n])
147
            || !in_array($tokens[$n][0], [T_DOUBLE_COLON, T_NEW], true);
148
    }
149
}
150