Imagine a method is like a “Choose Your Own Adventure” book. Every time there is an if, else, switch, or loop, the reader has to keep track of a new path the story could take.
Cyclomatic Complexity is just a fancy way of counting how many different paths exist through your code.
The rule starts at 1, and adds +1 for every “branching” word it sees:
if or elseif is +1 path.case in a switch is +1 path.for, foreach, while) is +1 path.catch block is +1 path.If your score gets too high (default > 10), it means your method has too many possible stories. It’s too hard to test, and too hard for a human to read!
This code has so many if statements that it’s impossible to know all the outcomes.
public function getChapter(int $number, Character $character): bool {
if ($number > 0) { // +1 path
switch ($number) {
case 1: // +1 path
case 2: // +1 path
if ($character->isAlive()) { // +1 path
return true;
}
break;
}
if ($character->hasSword()) { // +1 path
if ($character->isStrong()) { // +1 path
return true;
}
}
}
return false;
}
We can flatten this by extracting logic or returning early. Now there are fewer paths to think about at once!
public function getChapter(int $number, Character $character): bool {
if ($number <= 0) {
return false;
}
if ($this->isEarlyChapter($number) && $character->isAlive()) {
return true;
}
return $character->hasSword() && $character->isStrong();
}
private function isEarlyChapter(int $number): bool {
return $number === 1 || $number === 2;
}
rules:
E0009:
max_complexity: 10
If Phanalist flags your method for Cyclomatic Complexity, it means your method is trying to make too many decisions. Break the complex parts out into smaller, well-named helper methods!