PhpFunctionsScanner   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 188
rs 9.92
c 0
b 0
f 0
wmc 31
lcom 1
cbo 4

5 Methods

Rating   Name   Duplication   Size   Complexity  
A enableCommentsExtraction() 0 4 1
A disableCommentsExtraction() 0 4 1
A __construct() 0 11 2
F getFunctions() 0 105 23
A parsePhpComment() 0 17 4
1
<?php
2
3
namespace Gettext\Utils;
4
5
use Gettext\Extractors\PhpCode;
6
7
class PhpFunctionsScanner extends FunctionsScanner
8
{
9
    /**
10
     * PHP tokens of the code to be parsed.
11
     *
12
     * @var array
13
     */
14
    protected $tokens;
15
16
    /**
17
     * If not false, comments will be extracted.
18
     *
19
     * @var string|false|array
20
     */
21
    protected $extractComments = false;
22
23
    /**
24
     * Enable extracting comments that start with a tag (if $tag is empty all the comments will be extracted).
25
     *
26
     * @param mixed $tag
27
     */
28
    public function enableCommentsExtraction($tag = '')
29
    {
30
        $this->extractComments = $tag;
31
    }
32
33
    /**
34
     * Disable comments extraction.
35
     */
36
    public function disableCommentsExtraction()
37
    {
38
        $this->extractComments = false;
39
    }
40
41
    /**
42
     * Constructor.
43
     *
44
     * @param string $code The php code to scan
45
     */
46
    public function __construct($code)
47
    {
48
        $this->tokens = array_values(
49
            array_filter(
50
                token_get_all($code),
51
                function ($token) {
52
                    return !is_array($token) || $token[0] !== T_WHITESPACE;
53
                }
54
            )
55
        );
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function getFunctions(array $constants = [])
62
    {
63
        $count = count($this->tokens);
64
        /* @var ParsedFunction[] $bufferFunctions */
65
        $bufferFunctions = [];
66
        /* @var ParsedComment[] $bufferComments */
67
        $bufferComments = [];
68
        /* @var array $functions */
69
        $functions = [];
70
71
        for ($k = 0; $k < $count; ++$k) {
72
            $value = $this->tokens[$k];
73
74
            if (is_string($value)) {
75
                if (isset($bufferFunctions[0])) {
76
                    switch ($value) {
77
                        case ',':
78
                            $bufferFunctions[0]->nextArgument();
79
                            break;
80
                        case ')':
81
                            $functions[] = array_shift($bufferFunctions)->close();
82
                            break;
83
                        case '.':
84
                            break;
85
                        default:
86
                            $bufferFunctions[0]->stopArgument();
87
                            break;
88
                    }
89
                }
90
                continue;
91
            }
92
93
            switch ($value[0]) {
94
                case T_CONSTANT_ENCAPSED_STRING:
95
                    //add an argument to the current function
96
                    if (isset($bufferFunctions[0])) {
97
                        $bufferFunctions[0]->addArgumentChunk(PhpCode::convertString($value[1]));
98
                    }
99
                    break;
100
101
                case T_STRING:
102
                    if (isset($bufferFunctions[0])) {
103
                        if (isset($constants[$value[1]])) {
104
                            $bufferFunctions[0]->addArgumentChunk($constants[$value[1]]);
105
                            break;
106
                        }
107
108
                        if (strtolower($value[1]) === 'null') {
109
                            $bufferFunctions[0]->addArgumentChunk(null);
110
                            break;
111
                        }
112
113
                        $bufferFunctions[0]->stopArgument();
114
                    }
115
116
                    //new function found
117
                    for ($j = $k + 1; $j < $count; ++$j) {
118
                        $nextToken = $this->tokens[$j];
119
120
                        if (is_array($nextToken) && $nextToken[0] === T_COMMENT) {
121
                            continue;
122
                        }
123
124
                        if ($nextToken === '(') {
125
                            $newFunction = new ParsedFunction($value[1], $value[2]);
126
127
                            // add comment that was on the line before.
128
                            if (isset($bufferComments[0])) {
129
                                $comment = $bufferComments[0];
130
131
                                if ($comment->isRelatedWith($newFunction)) {
132
                                    $newFunction->addComment($comment->getComment());
133
                                }
134
                            }
135
136
                            array_unshift($bufferFunctions, $newFunction);
137
                            $k = $j;
138
                        }
139
                        break;
140
                    }
141
                    break;
142
143
                case T_COMMENT:
144
                    $comment = $this->parsePhpComment($value[1], $value[2]);
145
146
                    if ($comment) {
147
                        array_unshift($bufferComments, $comment);
148
149
                        // The comment is inside the function call.
150
                        if (isset($bufferFunctions[0])) {
151
                            $bufferFunctions[0]->addComment($comment->getComment());
152
                        }
153
                    }
154
                    break;
155
156
                default:
157
                    if (isset($bufferFunctions[0])) {
158
                        $bufferFunctions[0]->stopArgument();
159
                    }
160
                    break;
161
            }
162
        }
163
164
        return $functions;
165
    }
166
167
    /**
168
     * Extract the actual text from a PHP comment.
169
     *
170
     * If set, only returns comments that match the prefix(es).
171
     *
172
     * @param string $value The PHP comment.
173
     * @param int $line Line number.
174
     *
175
     * @return null|ParsedComment Comment or null if comment extraction is disabled or if there is a prefix mismatch.
176
     */
177
    protected function parsePhpComment($value, $line)
178
    {
179
        if ($this->extractComments === false) {
180
            return null;
181
        }
182
183
        //this returns a comment or null
184
        $comment = ParsedComment::create($value, $line);
185
186
        $prefixes = array_filter((array) $this->extractComments);
187
188
        if ($comment && $comment->checkPrefixes($prefixes)) {
189
            return $comment;
190
        }
191
192
        return null;
193
    }
194
}
195