Switch Statement Smell
debt(d5/e7/b7/t5)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpmd and phpstan as the tools, both specialist static analysis tools that must be explicitly configured. A default linter won't flag switch statements as smells; it requires a dedicated code-smell ruleset to surface the pattern.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes replacing a type-switch with a Strategy pattern or entity method, and common_mistakes explicitly call out the same switch appearing in multiple places — 'shotgun surgery'. This is not a single-file fix; it requires creating a shared interface, implementing per-type classes, and removing the switch in every location it appears across the codebase.
Closest to 'strong gravitational pull' (b7). The smell applies to web, cli, and queue-worker contexts. Because the same switch logic is duplicated in multiple methods and must be updated everywhere a new type is added (violating OCP), every future feature or type addition is shaped by this structural choice. It imposes an ongoing tax on many work streams until addressed.
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field is explicit: developers believe switch statements are always a smell, when in fact only type-dispatching duplicated across the codebase is the problem. Simple data lookups and exhaustive enum matches are fine. This is a well-documented but commonly misunderstood nuance that misleads competent developers who over-apply the rule.
Also Known As
TL;DR
Explanation
Switch statements on a type or status field scattered across a codebase indicate that object-oriented polymorphism is the appropriate design. Each time a new type is added, every switch must be updated — a violation of the Open/Closed Principle. The refactoring is Replace Conditional with Polymorphism: create a class hierarchy where each subclass provides its own implementation of the varying behaviour. PHP 8.0's match expression is not a remedy for this smell — it's a better syntax for the same structural problem.
Common Misconception
Why It Matters
Common Mistakes
- Type-switching on a string, integer, or enum that represents a known set of types — use polymorphism instead.
- The same switch appearing in multiple places across the codebase — shotgun surgery.
- Not using match expressions in PHP 8 which at least provide exhaustiveness checking.
- Switch on type in service code when the decision should be in the domain object itself.
Code Examples
// Switch on type — must update for every new animal
function makeSound(string $type): string {
switch ($type) {
case 'dog': return 'Woof';
case 'cat': return 'Meow';
default: return '???';
}
}
// Polymorphism — each class knows its own behaviour
interface Animal { public function makeSound(): string; }
class Dog implements Animal { public function makeSound(): string { return 'Woof'; } }
class Cat implements Animal { public function makeSound(): string { return 'Meow'; } }
function play(Animal $a): void { echo $a->makeSound(); }
// Caller never changes when a new animal is added