Halstead::calculate()   B
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 47
Code Lines 37

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 47
rs 8.6846
cc 4
eloc 37
nc 2
nop 1
1
<?php
2
3
/*
4
 * (c) Jean-François Lépine <https://twitter.com/Halleck45>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Hal\Metrics\Complexity\Text\Halstead;
11
use Hal\Component\Token\TokenType;
12
13
14
/**
15
 * Calculates Halstead complexity
16
 *
17
 *      According Wikipedia, "Halstead complexity measures are software metrics introduced by Maurice Howard Halstead in
18
 *      1977 as part of his treatise on establishing an empirical science of software development.
19
 *      Halstead makes the observation that metrics of the software should reflect the implementation or
20
 *      expression of algorithms in different languages, but be independent of their execution on a specific platform.
21
 *      These metrics are therefore computed statically from the code."
22
 *
23
 * @author Jean-François Lépine <https://twitter.com/Halleck45>
24
 */
25
class Halstead {
26
27
    /**
28
     * Operators
29
     *
30
     * @var array
31
     */
32
    private $operators = array();
33
34
    /**
35
     *
36
     * Operands
37
     *
38
     * @var array
39
     */
40
    private $operands = array();
41
42
    /**
43
     * Allows to determine what is the type of tokens
44
     *
45
     * @var TokenType
46
     */
47
    private $tokenType;
48
49
    /**
50
     * Tokenizer
51
     *
52
     * @var \Hal\Component\Token\Tokenizer
53
     */
54
    private $tokenizer;
55
56
    /**
57
     * Constructor
58
     *
59
     * @param \Hal\Component\Token\Tokenizer $tokenizer
60
     * @param \Hal\Component\Token\TokenType $tokenType
61
     */
62
    public function __construct(\Hal\Component\Token\Tokenizer $tokenizer, \Hal\Component\Token\TokenType $tokenType)
63
    {
64
        $this->tokenizer = $tokenizer;
65
        $this->tokenType = $tokenType;
66
    }
67
68
    /**
69
     * Inventories tokens
70
     *
71
     * @param string $filename
72
     * @return $this
73
     */
74
    private function inventory($filename)
75
    {
76
        $this->operators = $this->operands = array();
77
78
        $tokens = $this->tokenizer->tokenize($filename);
79
80
        foreach($tokens as $token) {
81
            if($this->tokenType->isOperator($token)) {
82
                $this->operators[] = $token;
83
            }
84
            else if($this->tokenType->isOperand($token)) {
85
                $this->operands[] = $token;
86
            }
87
        }
88
        return $this;
89
    }
90
91
    /**
92
     * Calculate Halstead metrics
93
     *
94
     * @param $filename
95
     * @return Result
96
     */
97
    public function calculate($filename)
98
    {
99
        $this->inventory($filename);
100
        $result = new Result;
101
102
        $uniqueOperators = array_map( 'unserialize', array_unique( array_map( 'serialize', $this->operators ) ) );
103
        $uniqueOperands = array_map( 'unserialize', array_unique( array_map( 'serialize', $this->operands ) ) );
104
105
        $n1 = sizeof($uniqueOperators, COUNT_NORMAL);
106
        $n2 = sizeof($uniqueOperands, COUNT_NORMAL);
107
        $N1 = sizeof($this->operators, COUNT_NORMAL);
108
        $N2 = sizeof($this->operands, COUNT_NORMAL);
109
110
        if(($n2 == 0)||($N2 == 0)||($n2 == 2)) {
111
            // files without operators
112
            $V = $n1 = $n2 = $N1 = $N2 = $E = $D = $B = $T = $I = $L = 0;
113
        } else {
114
            $devAbility = 3000;
115
            $N = $N1 + $N2;
116
            $n = $n1 + $n2;
117
            $V = $N * log($n ,2);
118
            $L = (2 / max(1,$n1)) * ($n2 / $N2);
119
            $D = ($n1 / 2) * ($N2 / $n2);
120
            $E = $V * $D;
121
            $B = $V / $devAbility;
122
            $T = $E / 18;
123
            $I = $L * $V;
124
        }
125
126
        $result
127
            ->setLength($N1 + $N2)
128
            ->setVocabulary($n1 + $n2)
129
            ->setVolume(round($V,2))
130
            ->setDifficulty(round($D,2))
131
            ->setEffort(round($E,2))
132
            ->setLevel(round($L, 2))
133
            ->setBugs(round($B, 2))
134
            ->setTime(round($T))
135
            ->setIntelligentContent(round($I,2))
136
            ->setNumberOfOperators($N1)
137
            ->setNumberOfOperands($N2)
138
            ->setNumberOfUniqueOperators($n1)
139
            ->setNumberOfUniqueOperands($n2)
140
        ;
141
142
        return $result;
143
    }
144
};