Skip to content

Commit 10b90f7

Browse files
authored
Merge pull request #5 from smeghead/feature/parse-asign
feat: When determining the local variable severity, the coefficients …
2 parents 56955a3 + f7caabc commit 10b90f7

File tree

9 files changed

+118
-4
lines changed

9 files changed

+118
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
### Features
4+
5+
* When determining the local variable severity, the coefficients are now taken into account when the variable is an assignment.
6+
37
### Bug fix
48

59
* Refactor remove interface Scope

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ composer require --dev smeghead/php-variable-hard-usage
4141
```
4242

4343
## Usage
44-
44+
66 + 32 + 66
4545
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.
4646

4747
```bash
@@ -84,4 +84,40 @@ $ vendor/bin/php-variable-hard-usage somewhere/your-php-file.php
8484
}
8585
```
8686

87+
## How to calculate VariableHardUsage
88+
89+
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.
90+
91+
### Calculation Procedure
92+
93+
1. Obtain the line numbers of the variables:.
94+
95+
* Obtains the line numbers of all variables used in the function.
96+
97+
2. Calculate the average of the line numbers.
98+
99+
* Calculates the average of the retrieved line numbers. This is obtained by dividing the sum of the line numbers by the number of variables.
100+
101+
3. Calculate VariableHardUsage.
102+
103+
* For each variable, the absolute difference between the line number and the average line number is calculated.
104+
* If a variable is assigned, the difference is multiplied by a factor (2 by default).
105+
* Sum all these values to obtain VariableHardUsage.
106+
107+
### EXAMPLE.
108+
109+
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.
110+
111+
* Variable A: Row 10, with assignment
112+
* Variable B: Row 20, no assignment
113+
* Variable C: Row 30, with assignment
114+
115+
In this case, VariableHardUsage is calculated as follows
116+
117+
* Variable A: |10 - 20| * 2 = 20
118+
* Variable B: |20 - 20| * 1 = 0
119+
* Variable C: |30 - 20| * 2 = 20
120+
121+
Summing these, VariableHardUsage is 20 + 0 + 20 = 40.
87122

123+
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.

src/Analyze/VariableAnalyzer.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
final class VariableAnalyzer
1111
{
12+
private const ASSIGNED_VARIABLE_COEFFICIENT = 2;
13+
1214
/**
1315
* @var list<Func>
1416
*/
@@ -50,7 +52,7 @@ private function calcVariableHardUsage(array $vars): int
5052
{
5153
$lineNumbers = array_map(fn($var) => $var->lineNumber, $vars);
5254
$avarageLinuNumber = intval(array_sum($lineNumbers) / count($lineNumbers));
53-
$variableHardUsage = array_sum(array_map(fn($lineNumber) => abs($lineNumber - $avarageLinuNumber), $lineNumbers));
55+
$variableHardUsage = array_sum(array_map(fn(VarReference $var) => abs($var->lineNumber - $avarageLinuNumber) * ($var->assigned ? self::ASSIGNED_VARIABLE_COEFFICIENT : 1), $vars));
5456
return $variableHardUsage;
5557
}
5658
}

src/Parse/VarReference.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ final class VarReference
99
public function __construct(
1010
public readonly string $name,
1111
public readonly int $lineNumber,
12-
public readonly bool $updated = false
12+
public readonly bool $assigned = false
1313
)
1414
{
1515
}

src/Parse/VariableParser.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ private function collectParseResultPerFunctionLike(array $functionLikes): array
7575

7676
$variables = $this->nodeFinder->findInstanceOf($function, Variable::class);
7777
foreach ($variables as $variable) {
78-
$func->addVariable(new VarReference($variable->name, $variable->getLine())); // @phpstan-ignore-line
78+
$assigned = $variable->getAttribute('assigned');
79+
$func->addVariable(new VarReference($variable->name, $variable->getLine(), $assigned === true)); // @phpstan-ignore-line
7980
}
8081
return $func;
8182
}, $functionLikes);

src/Parse/Visitor/FunctionLikeFindingVisitor.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Smeghead\PhpVariableHardUsage\Parse\Visitor;
66

77
use PhpParser\Node;
8+
use PhpParser\Node\Expr\Assign;
89
use PhpParser\Node\FunctionLike;
910
use PhpParser\NodeVisitor\FindingVisitor;
1011
use PhpParser\Node\Stmt\Class_;
@@ -30,6 +31,9 @@ public function enterNode(Node $node) {
3031
$this->currentNamespace = $node->name ? $node->name->name : null;
3132
}
3233

34+
if ($node instanceof Assign) {
35+
$node->var->setAttribute('assigned', true); // Mark as assigned
36+
}
3337
if ($node instanceof FunctionLike) {
3438
$node->setAttribute('namespace', $this->currentNamespace);
3539
}

test/VariableAnalizerTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,22 @@ public function testAnalyzeFunctionLong(): void
4242
// abs(34 - 1) + abs(34 - 2) + abs(34 - 100) = 33 + 32 + 66 = 131
4343
$this->assertSame(131, $scopes[0]->getAnalyzedVariables()[0]->variableHardUsage);
4444
}
45+
46+
public function testAnalyzeFunctionLongAssignedVariable(): void
47+
{
48+
$func = new Func(null, 'testFunction');
49+
$func->addVariable(new VarReference('a', 1, true));
50+
$func->addVariable(new VarReference('a', 2));
51+
$func->addVariable(new VarReference('a', 100));
52+
53+
$sut = new VariableAnalyzer([$func]);
54+
$result = $sut->analyze();
55+
$scopes = $result->scopes;
56+
57+
$this->assertCount(1, $scopes);
58+
$this->assertSame('testFunction', $scopes[0]->name);
59+
// (1 + 2 + 100) / 3 = 34
60+
// abs(34 - 1) * 2 + abs(34 - 2) + abs(34 - 100) = 66 + 32 + 66 = 164
61+
$this->assertSame(164, $scopes[0]->getAnalyzedVariables()[0]->variableHardUsage);
62+
}
4563
}

test/VariableParserTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ public function testParseFunction(): void
2626
$vars = $functions[0]->getVariables();
2727
$this->assertSame('num', $vars[0]->name);
2828
$this->assertSame(5, $vars[0]->lineNumber, 'first $num (5)');
29+
$this->assertSame(true, $vars[0]->assigned, 'first $num (5) asign');
2930
$this->assertSame('num', $vars[1]->name);
3031
$this->assertSame(10, $vars[1]->lineNumber, 'second $num (10)');
32+
$this->assertSame(false, $vars[1]->assigned, 'second $num (10) not reference');
3133
}
3234

3335
public function testParseClass(): void

test/fixtures/sample_functions.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
// 酷使する関数
4+
function hardWordCount(string $text): int {
5+
$wordCount = 0;
6+
$currentWord = '';
7+
for ($i = 0; $i < strlen($text); $i++) {
8+
if ($text[$i] === ' ') {
9+
if ($currentWord !== '') {
10+
$wordCount++;
11+
$currentWord = '';
12+
}
13+
} else {
14+
$currentWord .= $text[$i];
15+
}
16+
}
17+
if ($currentWord !== '') {
18+
$wordCount++;
19+
}
20+
return $wordCount;
21+
}
22+
23+
// あまり酷使しない関数
24+
function lightWordCount(string $text): int {
25+
$words = explode(' ', $text);
26+
$wordCount = 0;
27+
foreach ($words as $word) {
28+
if ($word !== '') {
29+
$wordCount++;
30+
}
31+
}
32+
return $wordCount;
33+
}
34+
35+
// 全然酷使しない関数
36+
function niceWordCount(string $text): int {
37+
return count(array_filter(explode(' ', $text), fn($word) => $word !== ''));
38+
}
39+
40+
41+
42+
43+
$text = 'This is a pen.';
44+
45+
echo hardWordCount($text) . PHP_EOL;
46+
echo lightWordCount($text) . PHP_EOL;
47+
echo niceWordCount($text) . PHP_EOL;

0 commit comments

Comments
 (0)