Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Business/Cognitive/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Phauthentic\CognitiveCodeAnalysis\Business\Cognitive;

use Phauthentic\CognitiveCodeAnalysis\Business\Halstead\HalsteadMetricsCalculator;
use Phauthentic\CognitiveCodeAnalysis\CognitiveAnalysisException;
use Phauthentic\CognitiveCodeAnalysis\PhpParser\AnnotationVisitor;
use Phauthentic\CognitiveCodeAnalysis\PhpParser\CognitiveMetricsVisitor;
Expand All @@ -25,6 +26,7 @@ class Parser
protected CyclomaticComplexityVisitor $cyclomaticComplexityVisitor;
protected HalsteadMetricsVisitor $halsteadMetricsVisitor;
protected CombinedMetricsVisitor $combinedVisitor;
protected HalsteadMetricsCalculator $halsteadCalculator;

public function __construct(
ParserFactory $parserFactory,
Expand All @@ -44,7 +46,8 @@ public function __construct(
$this->cyclomaticComplexityVisitor->setAnnotationVisitor($this->annotationVisitor);
$this->traverser->addVisitor($this->cyclomaticComplexityVisitor);

$this->halsteadMetricsVisitor = new HalsteadMetricsVisitor();
$this->halsteadCalculator = new HalsteadMetricsCalculator();
$this->halsteadMetricsVisitor = new HalsteadMetricsVisitor($this->halsteadCalculator);
$this->halsteadMetricsVisitor->setAnnotationVisitor($this->annotationVisitor);
$this->traverser->addVisitor($this->halsteadMetricsVisitor);

Expand Down
106 changes: 106 additions & 0 deletions src/Business/Halstead/HalsteadMetricsCalculator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace Phauthentic\CognitiveCodeAnalysis\Business\Halstead;

/**
* @SuppressWarnings("PHPMD.ShortVariable")
*/
class HalsteadMetricsCalculator implements HalsteadMetricsCalculatorInterface
{
/**
* Calculate complete Halstead metrics for given operators and operands.
*
* @param array<string> $operators Array of operator types
* @param array<string> $operands Array of operand values
* @param string $identifier Identifier for the metrics (class name or method FQN)
* @return array<string, mixed> Array containing all Halstead metrics
*/
public function calculateMetrics(array $operators, array $operands, string $identifier): array
{
// Step 1: Count distinct and total occurrences of operators and operands
$distinctOperators = count(array_unique($operators));
$distinctOperands = count(array_unique($operands));
$totalOperators = count($operators);
$totalOperands = count($operands);

// Step 2: Calculate basic metrics
$programLength = $this->calculateProgramLength($totalOperators, $totalOperands);
$programVocabulary = $this->calculateProgramVocabulary($distinctOperators, $distinctOperands);

// Step 3: Calculate advanced metrics
$volume = $this->calculateVolume($programLength, $programVocabulary);
$difficulty = $this->calculateDifficulty($distinctOperators, $totalOperands, $distinctOperands);
$effort = $difficulty * $volume;

// Step 4: Prepare the results array
return [
'n1' => $distinctOperators,
'n2' => $distinctOperands,
'N1' => $totalOperators,
'N2' => $totalOperands,
'programLength' => $programLength,
'programVocabulary' => $programVocabulary,
'volume' => $volume,
'difficulty' => $difficulty,
'effort' => $effort,
'fqName' => $identifier,
];
}

/**
* Calculate the program length.
*
* @param int $N1 The total occurrences of operators
* @param int $N2 The total occurrences of operands
* @return int The program length
*/
public function calculateProgramLength(int $N1, int $N2): int
{
return $N1 + $N2;
}

/**
* Calculate the program vocabulary.
*
* @param int $n1 The count of distinct operators
* @param int $n2 The count of distinct operands
* @return int The program vocabulary
*/
public function calculateProgramVocabulary(int $n1, int $n2): int
{
return $n1 + $n2;
}

/**
* Calculate the volume of the program.
*
* @param int $programLength The length of the program
* @param int $programVocabulary The vocabulary of the program
* @return float The volume of the program
*/
public function calculateVolume(int $programLength, int $programVocabulary): float
{
if ($programVocabulary <= 0) {
return 0.0;
}
return $programLength * log($programVocabulary, 2);
}

/**
* Calculate the difficulty of the program.
*
* @param int $n1 The count of distinct operators
* @param int $N2 The total occurrences of operands
* @param int $n2 The count of distinct operands
* @return float The difficulty of the program
*/
public function calculateDifficulty(int $n1, int $N2, int $n2): float
{
if ($n2 === 0) {
return 0.0;
}
return ($n1 / 2) * ($N2 / $n2);
}
}
58 changes: 58 additions & 0 deletions src/Business/Halstead/HalsteadMetricsCalculatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Phauthentic\CognitiveCodeAnalysis\Business\Halstead;

/**
* @SuppressWarnings("PHPMD.ShortVariable")
*/
interface HalsteadMetricsCalculatorInterface
{
/**
* Calculate complete Halstead metrics for given operators and operands.
*
* @param array<string> $operators Array of operator types
* @param array<string> $operands Array of operand values
* @param string $identifier Identifier for the metrics (class name or method FQN)
* @return array<string, mixed> Array containing all Halstead metrics
*/
public function calculateMetrics(array $operators, array $operands, string $identifier): array;

/**
* Calculate the volume of the program.
*
* @param int $programLength The length of the program
* @param int $programVocabulary The vocabulary of the program
* @return float The volume of the program
*/
public function calculateVolume(int $programLength, int $programVocabulary): float;

/**
* Calculate the difficulty of the program.
*
* @param int $n1 The count of distinct operators
* @param int $N2 The total occurrences of operands
* @param int $n2 The count of distinct operands
* @return float The difficulty of the program
*/
public function calculateDifficulty(int $n1, int $N2, int $n2): float;

/**
* Calculate the program length.
*
* @param int $N1 The total occurrences of operators
* @param int $N2 The total occurrences of operands
* @return int The program length
*/
public function calculateProgramLength(int $N1, int $N2): int;

/**
* Calculate the program vocabulary.
*
* @param int $n1 The count of distinct operators
* @param int $n2 The count of distinct operands
* @return int The program vocabulary
*/
public function calculateProgramVocabulary(int $n1, int $n2): int;
}
5 changes: 4 additions & 1 deletion src/PhpParser/CombinedMetricsVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Phauthentic\CognitiveCodeAnalysis\PhpParser;

use Phauthentic\CognitiveCodeAnalysis\Business\Halstead\HalsteadMetricsCalculator;
use PhpParser\Node;
use PhpParser\NodeVisitor;

Expand All @@ -18,13 +19,15 @@ class CombinedMetricsVisitor implements NodeVisitor
private CognitiveMetricsVisitor $cognitiveVisitor;
private CyclomaticComplexityVisitor $cyclomaticVisitor;
private HalsteadMetricsVisitor $halsteadVisitor;
private HalsteadMetricsCalculator $halsteadCalculator;

public function __construct()
{
$this->annotationVisitor = new AnnotationVisitor();
$this->cognitiveVisitor = new CognitiveMetricsVisitor();
$this->cyclomaticVisitor = new CyclomaticComplexityVisitor();
$this->halsteadVisitor = new HalsteadMetricsVisitor();
$this->halsteadCalculator = new HalsteadMetricsCalculator();
$this->halsteadVisitor = new HalsteadMetricsVisitor($this->halsteadCalculator);
}

/**
Expand Down
Loading