Passed
Push — master ( ebba93...f0c8c9 )
by Alexander
02:18
created

UseStatementParser::fromFile()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7.2269

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 17
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 32
ccs 15
cts 18
cp 0.8333
crap 7.2269
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\VarDumper;
6
7
use RuntimeException;
8
9
use function defined;
10
11
/**
12
 * UseStatementParser given a PHP file, returns a set of `use` statements from the code.
13
 */
14
final class UseStatementParser
15
{
16
    /**
17
     * @param string $file File to read.
18
     *
19
     * @return array Use statements data.
20
     * @throws RuntimeException if there is a problem reading file.
21
     */
22 40
    public function fromFile(string $file): array
23
    {
24 40
        if (!file_exists($file)) {
25 1
            throw new RuntimeException('File "' . $file . '" does not exist.');
26
        }
27
28 39
        if (!is_readable($file)) {
29
            throw new RuntimeException('File "' . $file . '" is not readable.');
30
        }
31
32 39
        $fileContent = file_get_contents($file);
33
34 39
        if ($fileContent === false) {
35
            throw new RuntimeException('Failed to read file "' . $file . '".');
36
        }
37
38 39
        $tokens = token_get_all($fileContent);
39 39
        array_shift($tokens);
40
41 39
        $uses = [];
42 39
        foreach ($tokens as $i => $token) {
43 39
            if (!isset($token[0])) {
44
                continue;
45
            }
46
47 39
            if ($token[0] === T_USE) {
48 39
                $uses = array_merge($uses, $this->normalizeUse(array_slice($tokens, $i + 1)));
49 39
                continue;
50
            }
51
        }
52
53 39
        return $uses;
54
    }
55
56
    /**
57
     * Normalizes raw tokens into uniform use statement data.
58
     *
59
     * @param array $tokens Raw tokens.
60
     *
61
     * @return array Normalized use statement data.
62
     */
63 39
    private function normalizeUse(array $tokens): array
64
    {
65 39
        $commonNamespace = '\\';
66 39
        $current = '';
67 39
        $alias = null;
68 39
        $uses = [];
69
70 39
        foreach ($tokens as $token) {
71 39
            if (!isset($token[0])) {
72
                continue;
73
            }
74
            if (
75 39
                $token[0] === T_STRING
76 39
                || $token[0] === T_NS_SEPARATOR
77 39
                || (defined('T_NAME_QUALIFIED') && $token[0] === T_NAME_QUALIFIED)
78 39
                || (defined('T_NAME_FULLY_QUALIFIED') && $token[0] === T_NAME_FULLY_QUALIFIED)
79 39
                || (defined('T_NAME_RELATIVE') && $token[0] === T_NAME_RELATIVE)
80
            ) {
81 39
                $current .= $token[1];
82 39
                continue;
83
            }
84 39
            if ($token === ',' || $token === ';') {
85 39
                if ($current !== '') {
86 39
                    if ($alias === null) {
87 39
                        $uses[] = $commonNamespace . $current;
88
                    } else {
89
                        $uses[$alias] = $commonNamespace . $current;
90
                    }
91 39
                    $current = '';
92
                }
93
            }
94 39
            if ($token === ';') {
95 39
                break;
96
            }
97 39
            if ($token === '{') {
98 1
                $commonNamespace .= $current;
99 1
                $current = '';
100 1
                continue;
101
            }
102 39
            if ($token[0] === T_AS) {
103 31
                $current .= '@';
104
            }
105
        }
106
107 39
        return $this->replaceAliases($uses);
108
    }
109
110 39
    private function replaceAliases(array $uses): array
111
    {
112 39
        $result = [];
113 39
        foreach ($uses as $use) {
114 39
            $delimiterPosition = strpos($use, '@');
115 39
            if ($delimiterPosition !== false) {
116 31
                $alias = mb_substr($use, $delimiterPosition + 1);
117 31
                $result[$alias] = mb_substr($use, 0, $delimiterPosition);
118
            } else {
119 37
                $result[substr(strrchr($use, '\\'), 1)] = $use;
120
            }
121
        }
122
123 39
        return $result;
124
    }
125
}
126