Completed
Push — master ( 43d9d4...d1f171 )
by Igor
01:37
created

Tokenizer::resolveFullyQualifiedClassName()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 10
cts 10
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 7
nop 1
crap 5
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Leaditin\Annotations;
6
7
/**
8
 * Class Tokenizer
9
 *
10
 * @package Leaditin\Annotations
11
 * @author Igor Vuckovic
12
 */
13
class Tokenizer
14
{
15
    /** @var \ReflectionClass */
16
    protected $reflectionClass;
17
18
    /** @var array */
19
    protected $tokens;
20
21
    /** @var array */
22
    protected $structure;
23
24
    /**
25
     * @param \ReflectionClass $reflectionClass
26
     */
27 11
    public function __construct(\ReflectionClass $reflectionClass)
28
    {
29 11
        $this->reflectionClass = $reflectionClass;
30 11
        $this->tokens = token_get_all(file_get_contents($this->reflectionClass->getFileName()));
31 11
        $this->structure = [];
32 11
    }
33
34
    /**
35
     * @param string $name
36
     * @return string
37
     */
38 10
    public function resolveFullyQualifiedClassName(string $name) : string
39
    {
40 10
        $length = strlen($name);
41
42 10
        foreach ($this->getUseNames() as $fullyQualifiedClassName => $useClassName) {
43 10
            if (substr($useClassName, -$length) === $name) {
44 10
                return $fullyQualifiedClassName;
45
            }
46
        }
47
48 8
        if (0 !== strpos($name, '\\')) {
49 8
            $fullyQualifiedClassName = "{$this->reflectionClass->getNamespaceName()}\\$name";
50 8
            if (class_exists($fullyQualifiedClassName)) {
51 7
                return $this->trimClassName($fullyQualifiedClassName);
52
            }
53
        }
54
55 7
        return $this->trimClassName($name);
56
    }
57
58
    /**
59
     * @param string $name
60
     * @return string
61
     */
62 7
    public function resolveVariableName(string $name) : string
63
    {
64 7
        if ($this->isScalar($name)) {
65 1
            return $name;
66
        }
67
68 6
        if ($this->isSelf($name)) {
69 6
            return $this->trimClassName($this->reflectionClass->name);
70
        }
71
72 6
        return $name;
73
    }
74
75
    /**
76
     * @return array
77
     */
78 10
    protected function getUseNames() : array
79
    {
80 10
        if (!array_key_exists('use', $this->structure)) {
81 10
            $numberOfTokens = count($this->tokens);
82 10
            $this->structure['use'] = [];
83
84 10
            for ($i = 0; $i < $numberOfTokens; ++$i) {
85 10
                $this->readToken($i, $numberOfTokens);
86
            }
87
        }
88
89 10
        return $this->structure['use'];
90
    }
91
92
    /**
93
     * @param int $tokenPosition
94
     * @param int $numberOfTokens
95
     */
96 10
    protected function readToken(int $tokenPosition, int $numberOfTokens)
97
    {
98 10
        if ($this->tokens[$tokenPosition][0] !== T_USE) {
99 10
            return;
100
        }
101
102 10
        $class = '';
103 10
        for ($j = $tokenPosition + 1; $j < $numberOfTokens; ++$j) {
104 10
            $this->useToken($j, $class);
105
        }
106 10
    }
107
108
    /**
109
     * @param int $tokenPosition
110
     * @param string $class
111
     */
112 10
    protected function useToken(int $tokenPosition, string &$class)
113
    {
114 10
        if ($this->tokens[$tokenPosition][0] === T_STRING) {
115 10
            $class .= '\\' . $this->tokens[$tokenPosition][1];
116 10
        } elseif ($this->tokens[$tokenPosition] === ';') {
117 10
            $this->useClass($class);
118
        }
119 10
    }
120
121
    /**
122
     * @param string $class
123
     */
124 10
    protected function useClass(string &$class)
125
    {
126 10
        $fullyQualifiedClassName = $this->deriveFullyQualifiedClassName($class);
127 10
        $this->structure['use'][$this->trimClassName($fullyQualifiedClassName)] = $this->trimClassName($class);
128 10
        $class = '';
129 10
    }
130
131
    /**
132
     * @param string $className
133
     * @return string
134
     */
135 10
    protected function deriveFullyQualifiedClassName(string $className) : string
136
    {
137 10
        while (!class_exists($className)) {
138 10
            $length = strrpos($className, '\\');
139 10
            if ($length === false) {
140 10
                return $className;
141
            }
142
143 10
            $className = substr($className, 0, $length);
144
        }
145
146 10
        return $className;
147
    }
148
149
    /**
150
     * @param string $name
151
     * @return bool
152
     */
153 7
    protected function isScalar(string $name) : bool
154
    {
155
        $scalars = [
156 7
            'int', 'integer',
157
            'bool', 'boolean',
158
            'string', 'array',
159
            'float', 'double', 'decimal',
160
        ];
161
162 7
        return in_array($name, $scalars, false);
163
    }
164
165
    /**
166
     * @param string $name
167
     * @return bool
168
     */
169 6
    protected function isSelf(string $name) : bool
170
    {
171
        $selves = [
172 6
            'self',
173
            'static',
174
            '$this'
175
        ];
176
177 6
        return in_array($name, $selves, false);
178
    }
179
180
    /**
181
     * @param string $name
182
     * @return string
183
     */
184 10
    protected function trimClassName(string $name) : string
185
    {
186 10
        return ltrim($name, '\\');
187
    }
188
}
189