Completed
Pull Request — master (#370)
by Löki
04:56
created

ExternalsVisitor::leaveNode()   F

Complexity

Conditions 27
Paths 2080

Size

Total Lines 97

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
nc 2080
nop 1
dl 0
loc 97
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Hal\Metric\Class_\Coupling;
3
4
use Hal\Metric\Helper\MetricClassNameGenerator;
5
use Hal\Metric\Metrics;
6
use PhpParser\Node;
7
use PhpParser\Node\Stmt;
8
use PhpParser\NodeVisitorAbstract;
9
10
/**
11
 * List externals dependencies
12
 *
13
 * Class ExternalsVisitor
14
 * @package Hal\Metric\Class_\Coupling
15
 */
16
class ExternalsVisitor extends NodeVisitorAbstract
17
{
18
19
    /**
20
     * @var Metrics
21
     */
22
    private $metrics;
23
24
    /**
25
     * @var Stmt\UseUse[]
26
     */
27
    private $uses = [];
28
29
    /**
30
     * ClassEnumVisitor constructor.
31
     * @param Metrics $metrics
32
     */
33
    public function __construct(Metrics $metrics)
34
    {
35
        $this->metrics = $metrics;
36
    }
37
38
    /**
39
     * @inheritdoc
40
     */
41
    public function leaveNode(Node $node)
42
    {
43
44
        if ($node instanceof Stmt\Namespace_) {
45
            $this->uses = [];
46
        }
47
48
        if ($node instanceof Stmt\Use_) {
49
            $this->uses = array_merge($this->uses, $node->uses);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->uses, $node->uses) of type array is incompatible with the declared type array<integer,object<PhpParser\Node\Stmt\UseUse>> of property $uses.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
50
        }
51
52
        if ($node instanceof Stmt\Class_
53
            || $node instanceof Stmt\Interface_
54
            || $node instanceof Stmt\Trait_
55
        ) {
56
57
            $class = $this->metrics->get(MetricClassNameGenerator::getName($node));
58
            $parents = [];
59
60
            $dependencies = [];
61
62
            // extends
63
            if (isset($node->extends)) {
64
                if (is_array($node->extends)) {
65
                    foreach ((array)$node->extends as $interface) {
66
                        $this->pushToDependencies($dependencies, (string)$interface);
67
                        array_push($parents, (string)$interface);
68
                    }
69
                } else {
70
                    $this->pushToDependencies($dependencies, (string)$node->extends);
71
                    array_push($parents, (string)$node->extends);
72
                }
73
            }
74
75
            // implements
76
            if (isset($node->implements)) {
77
                foreach ($node->implements as $interface) {
78
                    $this->pushToDependencies($dependencies, (string)$interface);
79
                }
80
            }
81
82
            foreach ($node->stmts as $stmt) {
83
                if ($stmt instanceof Stmt\ClassMethod) {
84
                    // return
85
                    if (isset($stmt->returnType)) {
86
                        if ($stmt->returnType instanceof Node\Name\FullyQualified) {
87
                            $this->pushToDependencies($dependencies, (string)$stmt->returnType);
88
                        }
89
                    }
90
91
                    // Type hint of method's parameters
92
                    foreach ($stmt->params as $param) {
93
                        if ($param->type) {
94
                            if ($param->type instanceof Node\Name\FullyQualified) {
95
                                $this->pushToDependencies($dependencies, (string)$param->type);
96
                            }
97
                        }
98
                    }
99
100
                    // instantiations, static calls
101
                    \iterate_over_node($stmt, function ($node) use (&$dependencies) {
102
                        switch (true) {
103
                            case $node instanceof Node\Expr\New_:
104
                                // new MyClass
105
                                $this->pushToDependencies($dependencies, getNameOfNode($node));
106
                                break;
107
                            case $node instanceof Node\Expr\StaticCall:
108
                                // MyClass::Call
109
                                $this->pushToDependencies($dependencies, getNameOfNode($node));
110
                                break;
111
                        }
112
                    });
113
114
                    // annotations
115
                    $comments = $stmt->getDocComment();
116
                    if ($comments && false !== preg_match_all('!\s+\*\s+@(\w+)!', $comments->getText(), $matches)) {
117
                        foreach ($matches[1] as $check) {
118
                            foreach ($this->uses as $use) {
119
                                if (method_exists($use, 'getAlias')) {
120
                                    if (((string) $use->getAlias()) === $check) {
121
                                        $this->pushToDependencies($dependencies, (string)($use->name));
122
                                    }
123
                                    continue;
124
                                }
125
                                if ($use->alias === $check) {
126
                                    $this->pushToDependencies($dependencies, (string)($use->name));
127
                                }
128
                            }
129
                        }
130
                    }
131
                }
132
            }
133
134
            $class->set('externals', $dependencies);
135
            $class->set('parents', $parents);
136
        }
137
    }
138
139
    private function pushToDependencies(array &$dependencies, $dependency)
140
    {
141
        $lowercase = strtolower($dependency);
142
        if ('self' === $lowercase || 'parent' === $lowercase) {
143
            return;
144
        }
145
        array_push($dependencies, (string) $dependency);
146
    }
147
}
148
149