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

Visitor Pattern

Code Quality PHP 5.0+ Advanced
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and the tool listed is phpstan, which can catch missing interface implementations but cannot reliably detect the misapplication of Visitor (e.g., using it when the hierarchy changes frequently, or using instanceof checks instead). The code pattern — scattered instanceof checks or modifications to every class when adding an operation — requires human review to recognise as a Visitor misuse rather than a compiler or linter error.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes defining accept() in each element class and implementing operations in Visitor classes. Retrofitting Visitor onto an existing hierarchy means touching every class to add accept(), creating a VisitorInterface, and writing visitor implementations — spanning multiple files. Conversely, removing a poorly applied Visitor also requires touching all element classes and consolidating logic.

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

Closest to 'persistent productivity tax' (b5). The pattern applies to web and cli contexts and affects the entire class hierarchy it targets. Once Visitor is in place, every new element class added to the hierarchy must implement accept() and every existing Visitor must be updated — creating an ongoing maintenance tax across multiple files. It shapes how operations are added to the hierarchy but doesn't define the whole system's architecture.

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 directly identifies the trap: developers believe Visitor requires modifying visited classes for each new operation, when in fact only one accept() method per class is needed and new operations are new Visitor implementations. Additionally, common_mistakes highlight confusion with Strategy and misuse when the hierarchy is unstable. These are well-documented gotchas but not catastrophically counterintuitive.

About DEBT scoring →

Also Known As

double dispatch

TL;DR

A behavioural pattern that separates an algorithm from the objects it operates on — adding new operations to a class hierarchy without modifying those classes.

Explanation

The Visitor pattern uses double dispatch: the object calls accept(visitor), which calls visitor.visit(this). This allows adding new operations to a stable class hierarchy by writing new Visitor classes rather than adding methods to each node. Common uses: abstract syntax tree traversal, serialisation to different formats, static analysis tools, and document export. The trade-off: adding a new node type requires updating all existing visitors.

Common Misconception

Visitor requires modifying the visited classes — each class only needs one accept(VisitorInterface $v) method added once; all future operations are new Visitor implementations.

Why It Matters

Visitor allows adding new operations to a closed class hierarchy without modifying it — ideal for compilers, AST processors, and document renderers where operations change but the node types are stable.

Common Mistakes

  • Using Visitor when the class hierarchy changes frequently — each new class requires updating all visitors, which is more painful than adding a method to each class.
  • Not defining a VisitorInterface — without it, the pattern provides no type safety.
  • Confusing Visitor (new operations, stable classes) with Strategy (interchangeable algorithms, single class).
  • Implementing Visitor for simple trees where a recursive method on each node is simpler.

Code Examples

✗ Vulnerable
// Without visitor — adding export requires modifying every node:
class TextNode {
    public function toHtml(): string { /* ... */ }
    public function toPdf(): string { /* ... */ }  // Must add to every node class
    public function toMarkdown(): string { /* ... */ } // Keeps growing
}
✓ Fixed
// Visitor — add new export format without touching node classes:
interface NodeVisitor {
    public function visitText(TextNode $node): string;
    public function visitImage(ImageNode $node): string;
}

class TextNode {
    public function accept(NodeVisitor $v): string { return $v->visitText($this); }
}

class MarkdownExporter implements NodeVisitor {
    public function visitText(TextNode $n): string { return $n->content; }
    public function visitImage(ImageNode $n): string { return "![]({$n->src})"; }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 43
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 1 ping T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 8 Ahrefs 4 Scrapy 4 Perplexity 3 Google 3 Unknown AI 2 ChatGPT 2 Claude 2 Bing 2
crawler 27 crawler_json 3
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: High
⚡ Quick Fix
Use Visitor when you need to add new operations to a class hierarchy without modifying those classes — define accept() in each element, implement the operation in a Visitor class
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
New operation requires modifying every class in a hierarchy; instanceof checks to apply different behaviour per type
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update


✓ schema.org compliant