Php53Features::detectNamespaces()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 20
ccs 19
cts 19
cp 1
rs 8.8571
cc 6
eloc 15
nc 4
nop 1
crap 6
1
<?php
2
/**
3
 * Php53Features.php
4
 *
5
 * MIT LICENSE
6
 *
7
 * LICENSE: This source file is subject to the MIT license.
8
 * A copy of the licenses text was distributed alongside this
9
 * file (usually the repository or package root). The text can also
10
 * be obtained on one of the following sources:
11
 * * http://opensource.org/licenses/MIT
12
 * * https://github.com/suralc/pvra/blob/master/LICENSE
13
 *
14
 * @author     suralc <[email protected]>
15
 * @license    http://opensource.org/licenses/MIT  MIT
16
 */
17
18
namespace Pvra\Analysers;
19
20
use PhpParser\Node;
21
use Pvra\Result\Reason;
22
23
/**
24
 * Class Php53Features
25
 *
26
 * Used for the detection of the following elements:
27
 * * `goto` and Jump constructs
28
 * * Namespace related features
29
 * * NowDoc definitions
30
 * * Definitions of PHP 5.3+ magic methods and their explicit usage
31
 * * __DIR__ constant
32
 * * Short ternary
33
 * * Closure definition using `function() {}` syntax
34
 * * Late state binding
35
 *
36
 * @package Pvra\Analysers
37
 */
38
class Php53Features extends LanguageFeatureAnalyser
39
{
40
    /**
41
     * Stores the current in class state of this NodeVisitor.
42
     * This is required to detect the usage of doc-syntax usaged within class constant
43
     * definitions.
44
     *
45
     * @var bool
46
     */
47
    private $inClass = false;
48
49
    /**
50
     * @inheritdoc
51
     */
52 56
    public function enterNode(Node $node)
53
    {
54 56
        if ($this->isClassDeclarationStatement($node)) {
55 32
            $this->inClass = true;
56 16
        }
57 56
        if ($this->mode & self::MODE_ADDITION) {
58 52
            $this->detectGotoKeywordAndJumpLabel($node);
59 52
            $this->detectNamespaces($node);
60 52
            $this->detectNowDoc($node);
61 52
            $this->detectNewMagicDefinitions($node);
62 52
            $this->detectDocFormatConstantInitializationAndConstOutsideClass($node);
63 52
            $this->detectShortHandTernary($node);
64 52
            $this->detectClosures($node);
65 52
            $this->detectDynamicAccessToStatic($node);
66 52
            $this->detectLateStateBinding($node);
67 26
        }
68 56
        if ($this->mode & self::MODE_DEPRECATION) {
69 24
            $this->detectNewByReference($node);
70 12
        }
71 56
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76 56
    public function leaveNode(Node $node)
77
    {
78 56
        if ($this->isClassDeclarationStatement($node)) {
79 32
            $this->inClass = false;
80 16
        }
81 56
    }
82
83
    /**
84
     * @param \PhpParser\Node $node
85
     * @return bool
86
     */
87 56
    private function isClassDeclarationStatement(Node $node)
88
    {
89 56
        return $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Interface_ || $node instanceof Node\Stmt\Trait_;
90
    }
91
92
    /**
93
     * @param \PhpParser\Node $node
94
     */
95 52
    private function detectGotoKeywordAndJumpLabel(Node $node)
96
    {
97 52
        if ($node instanceof Node\Stmt\Goto_) {
98 4
            $this->getResult()->addRequirement(
99 4
                Reason::GOTO_KEYWORD,
100 4
                $node->getLine(),
101 4
                null,
102 4
                ['name' => $node->name]
103 2
            );
104 28
        } elseif ($node instanceof Node\Stmt\Label) {
105 4
            $this->getResult()->addRequirement(
106 4
                Reason::JUMP_LABEL,
107 4
                $node->getLine(),
108 4
                null,
109 4
                ['name' => $node->name]
110 2
            );
111 2
        }
112 52
    }
113
114
    /**
115
     * @param \PhpParser\Node $node
116
     */
117 52
    private function detectNamespaces(Node $node)
118
    {
119 52
        if ($node instanceof Node\Stmt\Namespace_) {
120 20
            $this->getResult()->addRequirement(
121 20
                Reason::NAMESPACE_DECLERATION,
122 20
                $node->getLine(),
123 20
                null,
124 20
                ['name' => isset($node->name) ? $node->name->toString() : '::global::']
125 10
            );
126 26
        } elseif ($node instanceof Node\Scalar\MagicConst\Namespace_) {
127 6
            $this->getResult()->addRequirement(Reason::NAMESPACE_MAGIC_CONSTANT, $node->getLine());
128 52
        } elseif ($node instanceof Node\Stmt\Use_ && $node->type === Node\Stmt\Use_::TYPE_NORMAL) {
129 8
            $this->getResult()->addRequirement(
130 8
                Reason::NAMESPACE_IMPORT,
131 8
                $node->getLine(),
132 8
                null,
133 8
                ['import_count' => count($node->uses)]
134 4
            );
135 4
        }
136 52
    }
137
138
    /**
139
     * @param \PhpParser\Node $node
140
     */
141 52
    private function detectNowDoc(Node $node)
142
    {
143 52
        if ($node->hasAttribute('isNowDoc') && $node instanceof Node\Scalar\String_) {
144 6
            $this->getResult()->addRequirement(Reason::NOWDOC_LITERAL, $node->getLine());
145 3
        }
146 52
    }
147
148
    /**
149
     * @param \PhpParser\Node $node
150
     */
151 52
    private function detectNewMagicDefinitions(Node $node)
152
    {
153 52
        if (($node instanceof Node\Stmt\ClassMethod && $node->isPublic())
154 52
            || ($node instanceof Node\Expr\MethodCall || $node instanceof Node\Expr\StaticCall)
155 52
            && is_string($node->name)
156 26
        ) {
157 20
            if (strcasecmp($node->name, '__callStatic') === 0) {
158 4
                $this->getResult()->addRequirement(Reason::CALLSTATIC_MAGIC_METHOD, $node->getLine());
159 20
            } elseif (strcasecmp($node->name, '__invoke') === 0) {
160 12
                $this->getResult()->addRequirement(Reason::INVOKE_MAGIC_METHOD, $node->getLine());
161 2
            }
162 35
        } elseif ($node instanceof Node\Scalar\MagicConst\Dir) {
163 2
            $this->getResult()->addRequirement(Reason::DIR_MAGIC_CONSTANT, $node->getLine());
164 1
        }
165 52
    }
166
167
    /**
168
     * @param \PhpParser\Node $node
169
     */
170 52
    private function detectDocFormatConstantInitializationAndConstOutsideClass(Node $node)
171
    {
172 52
        if ($node instanceof Node\Stmt\Const_) {
173 4
            if (!$this->inClass) {
174 4
                $this->getResult()->addRequirement(Reason::CONST_KEYWORD_OUTSIDE_CLASS, $node->getLine());
175 2
            }
176 2
        }
177 52
        if ($node instanceof Node\Stmt\Const_ || $node instanceof Node\Stmt\ClassConst) {
178 12
            foreach ($node->consts as $const) {
179 12
                if ($const->value->hasAttribute('isDocSyntax')) {
180 6
                    $this->getResult()->addRequirement(
181 6
                        Reason::CONST_KEYWORD_DOC_SYNTAX,
182 6
                        $const->value->getLine(),
183 6
                        null,
184 9
                        ['name' => $const->name]
185 3
                    );
186 3
                }
187 6
            }
188 6
        }
189 52
    }
190
191
    /**
192
     * @param \PhpParser\Node $node
193
     */
194 52
    private function detectShortHandTernary(Node $node)
195
    {
196 52
        if ($node instanceof Node\Expr\Ternary && $node->if === null) {
197 4
            $this->getResult()->addRequirement(Reason::SHORT_TERNARY, $node->getLine());
198 2
        }
199 52
    }
200
201
    /**
202
     * @param \PhpParser\Node $node
203
     */
204 52
    private function detectClosures(Node $node)
205
    {
206 52
        if ($node instanceof Node\Expr\Closure) {
207 16
            $this->getResult()->addRequirement(Reason::CLOSURE_DECLARATION, $node->getLine());
208 8
        }
209 52
    }
210
211
    /**
212
     * @param \PhpParser\Node $node
213
     */
214 52
    private function detectDynamicAccessToStatic(Node $node)
215
    {
216 52 View Code Duplication
        if (($node instanceof Node\Expr\StaticPropertyFetch || $node instanceof Node\Expr\StaticCall)
217 52
            && $node->class instanceof Node\Expr
218 26
        ) {
219 12
            $this->getResult()->addRequirement(Reason::DYNAMIC_ACCESS_TO_STATIC, $node->getLine());
220 6
        }
221 52
    }
222
223
    /**
224
     * @param \PhpParser\Node $node
225
     */
226 52
    private function detectLateStateBinding(Node $node)
227
    {
228 52
        if (($node instanceof Node\Expr\StaticPropertyFetch || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\ClassConstFetch)
229 52
            && $node->class instanceof Node\Name && strcasecmp($node->class->toString(), 'static') === 0
230 26
        ) {
231 4
            $this->getResult()->addRequirement(Reason::LATE_STATE_BINDING_USING_STATIC, $node->getLine());
232 2
        }
233 52
    }
234
235
    /**
236
     * @param \PhpParser\Node $node
237
     */
238 24
    private function detectNewByReference(Node $node)
239
    {
240 24
        if ($node instanceof Node\Expr\AssignRef && $node->expr instanceof Node\Expr\New_) {
241 2
            $this->getResult()->addLimit(Reason::NEW_ASSIGN_BY_REF_DEP, $node->getLine());
242 1
        }
243 24
    }
244
}
245