Passed
Pull Request — master (#39)
by Alexander
02:17
created

UseStatementParser   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Test Coverage

Coverage 95.83%

Importance

Changes 6
Bugs 1 Features 0
Metric Value
eloc 47
c 6
b 1
f 0
dl 0
loc 99
ccs 46
cts 48
cp 0.9583
rs 10
wmc 25

3 Methods

Rating   Name   Duplication   Size   Complexity  
A replaceAliases() 0 15 4
A fromFile() 0 18 4
C normalizeUse() 0 41 17
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\VarDumper;
6
7
use function defined;
8
9
/**
10
 * UseStatementParser given a PHP file, returns a set of `use` statements from the code.
11
 */
12
final class UseStatementParser
13
{
14
    /**
15
     * @param string $file File to read.
16
     *
17
     * @return array Use statements data.
18
     * @psalm-return array<string, string>
19
     */
20 34
    public function fromFile(string $file): array
21
    {
22 34
        $tokens = token_get_all(file_get_contents($file));
23 34
        array_shift($tokens);
24
25 34
        $uses = [];
26 34
        foreach ($tokens as $i => $token) {
27 34
            if (!isset($token[0])) {
28
                continue;
29
            }
30
31 34
            if ($token[0] === T_USE) {
32 34
                $uses = array_merge($uses, $this->normalizeUse(array_slice($tokens, $i + 1)));
33 34
                continue;
34
            }
35
        }
36
37 34
        return $uses;
38
    }
39
40
    /**
41
     * Normalizes raw tokens into uniform use statement data.
42
     *
43
     * @param array $tokens Raw tokens.
44
     *
45
     * @return array Normalized use statement data.
46
     * @psalm-return array<string, string>
47
     */
48 34
    private function normalizeUse(array $tokens): array
49
    {
50 34
        $commonNamespace = '\\';
51 34
        $current = '';
52 34
        $uses = [];
53
54
        /** @psalm-var array<int, int|string>|string $token */
55 34
        foreach ($tokens as $token) {
56 34
            if (!isset($token[0])) {
57
                continue;
58
            }
59
            if (
60 34
                $token[0] === T_STRING
61 34
                || $token[0] === T_NS_SEPARATOR
62 34
                || (defined('T_NAME_QUALIFIED') && $token[0] === T_NAME_QUALIFIED)
63 34
                || (defined('T_NAME_FULLY_QUALIFIED') && $token[0] === T_NAME_FULLY_QUALIFIED)
64 34
                || (defined('T_NAME_RELATIVE') && $token[0] === T_NAME_RELATIVE)
65
            ) {
66 34
                $current .= $token[1];
67 34
                continue;
68
            }
69 34
            if ($token === ',' || $token === ';') {
70 34
                if ($current !== '') {
71 34
                    $uses[] = $commonNamespace . $current;
72 34
                    $current = '';
73
                }
74
            }
75 34
            if ($token === ';') {
76 34
                break;
77
            }
78 34
            if ($token === '{') {
79 1
                $commonNamespace .= $current;
80 1
                $current = '';
81 1
                continue;
82
            }
83 34
            if ($token[0] === T_AS) {
84 31
                $current .= '@';
85
            }
86
        }
87
88 34
        return $this->replaceAliases($uses);
89
    }
90
91
    /**
92
     * @param array $uses
93
     * @psalm-param list<string> $uses
94
     * @return array<string, string>
95
     */
96 34
    private function replaceAliases(array $uses): array
97
    {
98 34
        $result = [];
99 34
        foreach ($uses as $use) {
100 34
            $delimiterPosition = strpos($use, '@');
101 34
            if ($delimiterPosition !== false) {
102 31
                $alias = mb_substr($use, $delimiterPosition + 1);
103 31
                $result[$alias] = mb_substr($use, 0, $delimiterPosition);
104
            } else {
105 32
                $part = strrchr($use, '\\');
106 32
                $result[$part === false ? $use : substr($part, 1)] = $use;
107
            }
108
        }
109
110 34
        return $result;
111
    }
112
}
113