Skip to content

Commit 13780fc

Browse files
Extracting Halstead Calculations from the Visitor (#63)
1 parent fa4393a commit 13780fc

File tree

8 files changed

+363
-161
lines changed

8 files changed

+363
-161
lines changed

src/Business/Cognitive/Parser.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Phauthentic\CognitiveCodeAnalysis\Business\Cognitive;
66

7+
use Phauthentic\CognitiveCodeAnalysis\Business\Halstead\HalsteadMetricsCalculator;
78
use Phauthentic\CognitiveCodeAnalysis\CognitiveAnalysisException;
89
use Phauthentic\CognitiveCodeAnalysis\PhpParser\AnnotationVisitor;
910
use Phauthentic\CognitiveCodeAnalysis\PhpParser\CognitiveMetricsVisitor;
@@ -25,6 +26,7 @@ class Parser
2526
protected CyclomaticComplexityVisitor $cyclomaticComplexityVisitor;
2627
protected HalsteadMetricsVisitor $halsteadMetricsVisitor;
2728
protected CombinedMetricsVisitor $combinedVisitor;
29+
protected HalsteadMetricsCalculator $halsteadCalculator;
2830

2931
public function __construct(
3032
ParserFactory $parserFactory,
@@ -44,7 +46,8 @@ public function __construct(
4446
$this->cyclomaticComplexityVisitor->setAnnotationVisitor($this->annotationVisitor);
4547
$this->traverser->addVisitor($this->cyclomaticComplexityVisitor);
4648

47-
$this->halsteadMetricsVisitor = new HalsteadMetricsVisitor();
49+
$this->halsteadCalculator = new HalsteadMetricsCalculator();
50+
$this->halsteadMetricsVisitor = new HalsteadMetricsVisitor($this->halsteadCalculator);
4851
$this->halsteadMetricsVisitor->setAnnotationVisitor($this->annotationVisitor);
4952
$this->traverser->addVisitor($this->halsteadMetricsVisitor);
5053

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phauthentic\CognitiveCodeAnalysis\Business\Halstead;
6+
7+
/**
8+
* @SuppressWarnings("PHPMD.ShortVariable")
9+
*/
10+
class HalsteadMetricsCalculator implements HalsteadMetricsCalculatorInterface
11+
{
12+
/**
13+
* Calculate complete Halstead metrics for given operators and operands.
14+
*
15+
* @param array<string> $operators Array of operator types
16+
* @param array<string> $operands Array of operand values
17+
* @param string $identifier Identifier for the metrics (class name or method FQN)
18+
* @return array<string, mixed> Array containing all Halstead metrics
19+
*/
20+
public function calculateMetrics(array $operators, array $operands, string $identifier): array
21+
{
22+
// Step 1: Count distinct and total occurrences of operators and operands
23+
$distinctOperators = count(array_unique($operators));
24+
$distinctOperands = count(array_unique($operands));
25+
$totalOperators = count($operators);
26+
$totalOperands = count($operands);
27+
28+
// Step 2: Calculate basic metrics
29+
$programLength = $this->calculateProgramLength($totalOperators, $totalOperands);
30+
$programVocabulary = $this->calculateProgramVocabulary($distinctOperators, $distinctOperands);
31+
32+
// Step 3: Calculate advanced metrics
33+
$volume = $this->calculateVolume($programLength, $programVocabulary);
34+
$difficulty = $this->calculateDifficulty($distinctOperators, $totalOperands, $distinctOperands);
35+
$effort = $difficulty * $volume;
36+
37+
// Step 4: Prepare the results array
38+
return [
39+
'n1' => $distinctOperators,
40+
'n2' => $distinctOperands,
41+
'N1' => $totalOperators,
42+
'N2' => $totalOperands,
43+
'programLength' => $programLength,
44+
'programVocabulary' => $programVocabulary,
45+
'volume' => $volume,
46+
'difficulty' => $difficulty,
47+
'effort' => $effort,
48+
'fqName' => $identifier,
49+
];
50+
}
51+
52+
/**
53+
* Calculate the program length.
54+
*
55+
* @param int $N1 The total occurrences of operators
56+
* @param int $N2 The total occurrences of operands
57+
* @return int The program length
58+
*/
59+
public function calculateProgramLength(int $N1, int $N2): int
60+
{
61+
return $N1 + $N2;
62+
}
63+
64+
/**
65+
* Calculate the program vocabulary.
66+
*
67+
* @param int $n1 The count of distinct operators
68+
* @param int $n2 The count of distinct operands
69+
* @return int The program vocabulary
70+
*/
71+
public function calculateProgramVocabulary(int $n1, int $n2): int
72+
{
73+
return $n1 + $n2;
74+
}
75+
76+
/**
77+
* Calculate the volume of the program.
78+
*
79+
* @param int $programLength The length of the program
80+
* @param int $programVocabulary The vocabulary of the program
81+
* @return float The volume of the program
82+
*/
83+
public function calculateVolume(int $programLength, int $programVocabulary): float
84+
{
85+
if ($programVocabulary <= 0) {
86+
return 0.0;
87+
}
88+
return $programLength * log($programVocabulary, 2);
89+
}
90+
91+
/**
92+
* Calculate the difficulty of the program.
93+
*
94+
* @param int $n1 The count of distinct operators
95+
* @param int $N2 The total occurrences of operands
96+
* @param int $n2 The count of distinct operands
97+
* @return float The difficulty of the program
98+
*/
99+
public function calculateDifficulty(int $n1, int $N2, int $n2): float
100+
{
101+
if ($n2 === 0) {
102+
return 0.0;
103+
}
104+
return ($n1 / 2) * ($N2 / $n2);
105+
}
106+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phauthentic\CognitiveCodeAnalysis\Business\Halstead;
6+
7+
/**
8+
* @SuppressWarnings("PHPMD.ShortVariable")
9+
*/
10+
interface HalsteadMetricsCalculatorInterface
11+
{
12+
/**
13+
* Calculate complete Halstead metrics for given operators and operands.
14+
*
15+
* @param array<string> $operators Array of operator types
16+
* @param array<string> $operands Array of operand values
17+
* @param string $identifier Identifier for the metrics (class name or method FQN)
18+
* @return array<string, mixed> Array containing all Halstead metrics
19+
*/
20+
public function calculateMetrics(array $operators, array $operands, string $identifier): array;
21+
22+
/**
23+
* Calculate the volume of the program.
24+
*
25+
* @param int $programLength The length of the program
26+
* @param int $programVocabulary The vocabulary of the program
27+
* @return float The volume of the program
28+
*/
29+
public function calculateVolume(int $programLength, int $programVocabulary): float;
30+
31+
/**
32+
* Calculate the difficulty of the program.
33+
*
34+
* @param int $n1 The count of distinct operators
35+
* @param int $N2 The total occurrences of operands
36+
* @param int $n2 The count of distinct operands
37+
* @return float The difficulty of the program
38+
*/
39+
public function calculateDifficulty(int $n1, int $N2, int $n2): float;
40+
41+
/**
42+
* Calculate the program length.
43+
*
44+
* @param int $N1 The total occurrences of operators
45+
* @param int $N2 The total occurrences of operands
46+
* @return int The program length
47+
*/
48+
public function calculateProgramLength(int $N1, int $N2): int;
49+
50+
/**
51+
* Calculate the program vocabulary.
52+
*
53+
* @param int $n1 The count of distinct operators
54+
* @param int $n2 The count of distinct operands
55+
* @return int The program vocabulary
56+
*/
57+
public function calculateProgramVocabulary(int $n1, int $n2): int;
58+
}

src/PhpParser/CombinedMetricsVisitor.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Phauthentic\CognitiveCodeAnalysis\PhpParser;
66

7+
use Phauthentic\CognitiveCodeAnalysis\Business\Halstead\HalsteadMetricsCalculator;
78
use PhpParser\Node;
89
use PhpParser\NodeVisitor;
910

@@ -18,13 +19,15 @@ class CombinedMetricsVisitor implements NodeVisitor
1819
private CognitiveMetricsVisitor $cognitiveVisitor;
1920
private CyclomaticComplexityVisitor $cyclomaticVisitor;
2021
private HalsteadMetricsVisitor $halsteadVisitor;
22+
private HalsteadMetricsCalculator $halsteadCalculator;
2123

2224
public function __construct()
2325
{
2426
$this->annotationVisitor = new AnnotationVisitor();
2527
$this->cognitiveVisitor = new CognitiveMetricsVisitor();
2628
$this->cyclomaticVisitor = new CyclomaticComplexityVisitor();
27-
$this->halsteadVisitor = new HalsteadMetricsVisitor();
29+
$this->halsteadCalculator = new HalsteadMetricsCalculator();
30+
$this->halsteadVisitor = new HalsteadMetricsVisitor($this->halsteadCalculator);
2831
}
2932

3033
/**

0 commit comments

Comments
 (0)