Completed
Pull Request — master (#448)
by
unknown
08:31
created

SystemComplexityVisitor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Hal\Metric\Class_\Structural;
3
4
use Hal\Metric\Helper\MetricClassNameGenerator;
5
use Hal\Metric\MetricNullException;
6
use Hal\Metric\Metrics;
7
use PhpParser\Node;
8
use PhpParser\Node\Stmt;
9
use PhpParser\NodeVisitorAbstract;
10
11
/**
12
 * Calculates Card And Agresti metric
13
 *
14
 *      Fan-out = Structural fan-out = Number of other procedures this procedure calls
15
 *      v = number of input/output variables for a procedure
16
 *
17
 *      (SC) Structural complexity = fan-out^2
18
 *      (DC) Data complexity = v / (fan-out + 1)
19
 *
20
 * @author Jean-François Lépine <https://twitter.com/Halleck45>
21
 */
22
class SystemComplexityVisitor extends NodeVisitorAbstract
23
{
24
25
    /**
26
     * @var Metrics
27
     */
28
    private $metrics;
29
30
    /**
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
        if ($node instanceof Stmt\Class_ || $node instanceof Stmt\Trait_) {
44
            $name = MetricClassNameGenerator::getName($node);
45
            $class = $this->metrics->get($name);
46
            if ($class === null) {
47
                throw new MetricNullException($name, self::class);
48
            }
49
50
            $sy = $dc = $sc = [];
51
52
            foreach ($node->stmts as $stmt) {
53
                if ($stmt instanceof Stmt\ClassMethod) {
54
                    // number of returns and calls
55
                    $output = 0;
56
                    $fanout = [];
57
58
                    iterate_over_node($node, function ($node) use (&$output, &$fanout) {
59
                        switch (true) {
60
                            case $node instanceof Stmt\Return_:
61
                                $output++;
62
                                break;
63
                            case $node instanceof Node\Expr\StaticCall:
64
                            case $node instanceof Node\Expr\MethodCall:
65
                                array_push($fanout, getNameOfNode($node));
66
                        }
67
                    });
68
69
                    $fanout = count(array_unique($fanout));
70
                    $v = count($stmt->params) + $output;
71
                    $ldc = $v / ($fanout + 1);
72
                    $lsc = pow($fanout, 2);
73
                    $sy[] = $ldc + $lsc;
74
                    $dc[] = $ldc;
75
                    $sc[] = $lsc;
76
                }
77
            }
78
79
            // average for class
80
            $class
81
                ->set('relativeStructuralComplexity', empty($sc) ? 0 : round(array_sum($sc) / count($sc), 2))
82
                ->set('relativeDataComplexity', empty($dc) ? 0 : round(array_sum($dc) / count($dc), 2))
83
                ->set('relativeSystemComplexity', empty($sy) ? 0 : round(array_sum($sy) / count($sy), 2))
84
                ->set('totalStructuralComplexity', round(array_sum($sc), 2))
85
                ->set('totalDataComplexity', round(array_sum($dc), 2))
86
                ->set('totalSystemComplexity', round(array_sum($dc) + array_sum($sc), 2));
87
        }
88
89
        return null;
90
    }
91
}
92