1
|
|
|
<?php declare(strict_types = 1); |
2
|
|
|
|
3
|
|
|
namespace Churn\Assessors\CyclomaticComplexity; |
4
|
|
|
|
5
|
|
|
class CyclomaticComplexityAssessor |
6
|
|
|
{ |
7
|
|
|
/** |
8
|
|
|
* The total cyclomatic complexity score. |
9
|
|
|
* @var integer. |
10
|
|
|
*/ |
11
|
|
|
protected $score; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Asses the files cyclomatic complexity. |
15
|
|
|
* @param string $filePath Path and file name. |
16
|
|
|
* @return integer |
17
|
|
|
*/ |
18
|
|
|
public function assess($filePath): int |
19
|
|
|
{ |
20
|
|
|
$this->score = 0; |
21
|
|
|
|
22
|
|
|
$contents = $this->getFileContents($filePath); |
23
|
|
|
$this->countTheMethods($contents); |
24
|
|
|
$this->countTheIfStatements($contents); |
25
|
|
|
$this->countTheElseIfStatements($contents); |
26
|
|
|
$this->countTheWhileLoops($contents); |
27
|
|
|
$this->countTheForLoops($contents); |
28
|
|
|
|
29
|
|
|
$this->countTheCaseStatements($contents); |
30
|
|
|
|
31
|
|
|
if ($this->score == 0) { |
32
|
|
|
$this->score = 1; |
33
|
|
|
} |
34
|
|
|
return $this->score; |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Count how many methods there are. |
39
|
|
|
* @param string $contents Path and filename. |
40
|
|
|
* @return void |
41
|
|
|
*/ |
42
|
|
|
protected function countTheMethods($contents) |
43
|
|
|
{ |
44
|
|
|
preg_match("/[ ]function[ ]/", $contents, $matches); |
45
|
|
|
if (isset($matches[0])) { |
46
|
|
|
$this->score ++; |
47
|
|
|
} |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Count how many if statements there are. |
52
|
|
|
* @param string $contents Path and filename. |
53
|
|
|
* @return void |
54
|
|
|
*/ |
55
|
|
|
protected function countTheIfStatements($contents) |
56
|
|
|
{ |
57
|
|
|
$this->score += $this->howmAnyPatternMatches("/[ ]if[ ]{0,}\(/", $contents); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Count how many else if statements there are. |
62
|
|
|
* @param string $contents Path and filename. |
63
|
|
|
* @return void |
64
|
|
|
*/ |
65
|
|
|
protected function countTheElseIfStatements($contents) |
66
|
|
|
{ |
67
|
|
|
$this->score += $this->howmAnyPatternMatches("/else[ ]{0,}if[ ]{0,}\(/", $contents); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Count how many while loops there are. |
72
|
|
|
* @param string $contents Path and filename. |
73
|
|
|
* @return void |
74
|
|
|
*/ |
75
|
|
|
protected function countTheWhileLoops($contents) |
76
|
|
|
{ |
77
|
|
|
$this->score += $this->howmAnyPatternMatches("/while[ ]{0,}\(/", $contents); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Count how many for loops there are. |
82
|
|
|
* @param string $contents Path and filename. |
83
|
|
|
* @return void |
84
|
|
|
*/ |
85
|
|
|
protected function countTheForLoops($contents) |
86
|
|
|
{ |
87
|
|
|
// dd($this->howmAnyPatternMatches("/[ ]for(each){0,1}[ ]{0,}\(/", $contents)); |
|
|
|
|
88
|
|
|
$this->score += $this->howmAnyPatternMatches("/[ ]for(each){0,1}[ ]{0,}\(/", $contents); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Count how many case statements there are. |
93
|
|
|
* @param string $contents Path and filename. |
94
|
|
|
* @return void |
95
|
|
|
*/ |
96
|
|
|
protected function countTheCaseStatements($contents) |
97
|
|
|
{ |
98
|
|
|
$this->score += $this->howmAnyPatternMatches("/[ ]case[ ]{1}(.*)\:/", $contents); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* For the given $pattern on $string, how many matches are returned? |
103
|
|
|
* @param string $pattern Regex pattern. |
104
|
|
|
* @param string $string Any string. |
105
|
|
|
* @return integer |
106
|
|
|
*/ |
107
|
|
|
protected function howManyPatternMatches($pattern, $string): int |
108
|
|
|
{ |
109
|
|
|
preg_match_all($pattern, $string, $matches); |
110
|
|
|
if (isset($matches[0])) { |
111
|
|
|
return count($matches[0]); |
112
|
|
|
} |
113
|
|
|
return 0; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Return the contents of the provided file at $filePath. |
118
|
|
|
* @param string $filePath Path and filename. |
119
|
|
|
* @return string |
120
|
|
|
*/ |
121
|
|
|
protected function getFileContents($filePath): string |
122
|
|
|
{ |
123
|
|
|
return file_get_contents($filePath); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.