diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e7bad..a2a61e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +### Features + + * When determining the local variable severity, the coefficients are now taken into account when the variable is an assignment. + ### Bug fix * Refactor remove interface Scope diff --git a/README.md b/README.md index b02223e..9943404 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ composer require --dev smeghead/php-variable-hard-usage ``` ## Usage - +66 + 32 + 66 If you specify the path of the file for which you want to measure the local variable abuse and run the program, a report will be displayed in JSON format. ```bash @@ -84,4 +84,40 @@ $ vendor/bin/php-variable-hard-usage somewhere/your-php-file.php } ``` +## How to calculate VariableHardUsage + +VariableHardUsage is an index used to evaluate the frequency of use and scope of a local variable within a function. This indicator is calculated based on the variance of the line number at which the variable is used and the frequency with which the variable is assigned. + +### Calculation Procedure + +1. Obtain the line numbers of the variables:. + + * Obtains the line numbers of all variables used in the function. + +2. Calculate the average of the line numbers. + + * Calculates the average of the retrieved line numbers. This is obtained by dividing the sum of the line numbers by the number of variables. + +3. Calculate VariableHardUsage. + + * For each variable, the absolute difference between the line number and the average line number is calculated. + * If a variable is assigned, the difference is multiplied by a factor (2 by default). + * Sum all these values to obtain VariableHardUsage. + +### EXAMPLE. + +For example, suppose there are three variables in a function, each with row numbers 10, 20, and 30, and that some assignments are made and some are not made. In this case, the average row number is 20. + +* Variable A: Row 10, with assignment +* Variable B: Row 20, no assignment +* Variable C: Row 30, with assignment + +In this case, VariableHardUsage is calculated as follows + +* Variable A: |10 - 20| * 2 = 20 +* Variable B: |20 - 20| * 1 = 0 +* Variable C: |30 - 20| * 2 = 20 + +Summing these, VariableHardUsage is 20 + 0 + 20 = 40. +VariableHardUsage is thus calculated as a measure of the frequency of use and scope of a variable. This metric can be used to quantitatively evaluate the usage of local variables within a function and help improve code readability and maintainability. diff --git a/src/Analyze/VariableAnalyzer.php b/src/Analyze/VariableAnalyzer.php index 717547a..523f5d6 100644 --- a/src/Analyze/VariableAnalyzer.php +++ b/src/Analyze/VariableAnalyzer.php @@ -9,6 +9,8 @@ final class VariableAnalyzer { + private const ASSIGNED_VARIABLE_COEFFICIENT = 2; + /** * @var list */ @@ -50,7 +52,7 @@ private function calcVariableHardUsage(array $vars): int { $lineNumbers = array_map(fn($var) => $var->lineNumber, $vars); $avarageLinuNumber = intval(array_sum($lineNumbers) / count($lineNumbers)); - $variableHardUsage = array_sum(array_map(fn($lineNumber) => abs($lineNumber - $avarageLinuNumber), $lineNumbers)); + $variableHardUsage = array_sum(array_map(fn(VarReference $var) => abs($var->lineNumber - $avarageLinuNumber) * ($var->assigned ? self::ASSIGNED_VARIABLE_COEFFICIENT : 1), $vars)); return $variableHardUsage; } } \ No newline at end of file diff --git a/src/Parse/VarReference.php b/src/Parse/VarReference.php index 5e4b077..f5a7139 100644 --- a/src/Parse/VarReference.php +++ b/src/Parse/VarReference.php @@ -9,7 +9,7 @@ final class VarReference public function __construct( public readonly string $name, public readonly int $lineNumber, - public readonly bool $updated = false + public readonly bool $assigned = false ) { } diff --git a/src/Parse/VariableParser.php b/src/Parse/VariableParser.php index c3183b3..2dec85b 100644 --- a/src/Parse/VariableParser.php +++ b/src/Parse/VariableParser.php @@ -75,7 +75,8 @@ private function collectParseResultPerFunctionLike(array $functionLikes): array $variables = $this->nodeFinder->findInstanceOf($function, Variable::class); foreach ($variables as $variable) { - $func->addVariable(new VarReference($variable->name, $variable->getLine())); // @phpstan-ignore-line + $assigned = $variable->getAttribute('assigned'); + $func->addVariable(new VarReference($variable->name, $variable->getLine(), $assigned === true)); // @phpstan-ignore-line } return $func; }, $functionLikes); diff --git a/src/Parse/Visitor/FunctionLikeFindingVisitor.php b/src/Parse/Visitor/FunctionLikeFindingVisitor.php index 7357450..bc9fd8d 100644 --- a/src/Parse/Visitor/FunctionLikeFindingVisitor.php +++ b/src/Parse/Visitor/FunctionLikeFindingVisitor.php @@ -5,6 +5,7 @@ namespace Smeghead\PhpVariableHardUsage\Parse\Visitor; use PhpParser\Node; +use PhpParser\Node\Expr\Assign; use PhpParser\Node\FunctionLike; use PhpParser\NodeVisitor\FindingVisitor; use PhpParser\Node\Stmt\Class_; @@ -30,6 +31,9 @@ public function enterNode(Node $node) { $this->currentNamespace = $node->name ? $node->name->name : null; } + if ($node instanceof Assign) { + $node->var->setAttribute('assigned', true); // Mark as assigned + } if ($node instanceof FunctionLike) { $node->setAttribute('namespace', $this->currentNamespace); } diff --git a/test/VariableAnalizerTest.php b/test/VariableAnalizerTest.php index 47e3406..f0573ab 100644 --- a/test/VariableAnalizerTest.php +++ b/test/VariableAnalizerTest.php @@ -42,4 +42,22 @@ public function testAnalyzeFunctionLong(): void // abs(34 - 1) + abs(34 - 2) + abs(34 - 100) = 33 + 32 + 66 = 131 $this->assertSame(131, $scopes[0]->getAnalyzedVariables()[0]->variableHardUsage); } + + public function testAnalyzeFunctionLongAssignedVariable(): void + { + $func = new Func(null, 'testFunction'); + $func->addVariable(new VarReference('a', 1, true)); + $func->addVariable(new VarReference('a', 2)); + $func->addVariable(new VarReference('a', 100)); + + $sut = new VariableAnalyzer([$func]); + $result = $sut->analyze(); + $scopes = $result->scopes; + + $this->assertCount(1, $scopes); + $this->assertSame('testFunction', $scopes[0]->name); + // (1 + 2 + 100) / 3 = 34 + // abs(34 - 1) * 2 + abs(34 - 2) + abs(34 - 100) = 66 + 32 + 66 = 164 + $this->assertSame(164, $scopes[0]->getAnalyzedVariables()[0]->variableHardUsage); + } } \ No newline at end of file diff --git a/test/VariableParserTest.php b/test/VariableParserTest.php index 2577be2..46115f2 100644 --- a/test/VariableParserTest.php +++ b/test/VariableParserTest.php @@ -26,8 +26,10 @@ public function testParseFunction(): void $vars = $functions[0]->getVariables(); $this->assertSame('num', $vars[0]->name); $this->assertSame(5, $vars[0]->lineNumber, 'first $num (5)'); + $this->assertSame(true, $vars[0]->assigned, 'first $num (5) asign'); $this->assertSame('num', $vars[1]->name); $this->assertSame(10, $vars[1]->lineNumber, 'second $num (10)'); + $this->assertSame(false, $vars[1]->assigned, 'second $num (10) not reference'); } public function testParseClass(): void diff --git a/test/fixtures/sample_functions.php b/test/fixtures/sample_functions.php new file mode 100644 index 0000000..a4ae1de --- /dev/null +++ b/test/fixtures/sample_functions.php @@ -0,0 +1,47 @@ + $word !== '')); +} + + + + +$text = 'This is a pen.'; + +echo hardWordCount($text) . PHP_EOL; +echo lightWordCount($text) . PHP_EOL; +echo niceWordCount($text) . PHP_EOL;