← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Switch Statement Smell

Code Quality Intermediate
debt(d5/e7/b7/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

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.

e7 Effort Remediation debt — work required to fix once spotted

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.

b7 Burden Structural debt — long-term weight of choosing wrong

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.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

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.

About DEBT scoring →

Also Known As

switch statement smell type switch conditional dispatch

TL;DR

Repeated switch/if-elseif chains on the same type indicator signal a missing polymorphic design.

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

Switch statements are always a code smell. Simple data lookups and exhaustive enum matches are perfectly fine uses of switch. The smell is when switch on a type tag duplicates logic across the codebase that polymorphism would centralise.

Why It Matters

A switch on object type is often a missed polymorphism opportunity — it must be updated everywhere the type distinction matters, violating Open/Closed Principle.

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

✗ Vulnerable
// 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 '???';
    }
}
✓ Fixed
// 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

Added 15 Mar 2026
Edited 22 Mar 2026
Views 132
Rate this term
No ratings yet
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: High
⚡ Quick Fix
A switch on a type field often means missing polymorphism — replace it with a Strategy pattern or a method on the entity itself; each case becomes a class with a shared interface
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
switch($type) with many cases in multiple places; same switch logic duplicated in multiple methods; switch that grows every time a new type is added
Auto-detectable: ✓ Yes phpmd phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update


✓ schema.org compliant