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

Command Pattern

quality PHP 5.0+ Intermediate
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). PHPStan is listed but cannot automatically detect when the Command pattern should be used — it can only enforce rules on existing commands. The detection_hints note 'automated: no' and the code_pattern describes duplicated logic across controllers and queue jobs, which requires manual code review to identify. No static analysis tool reliably catches missing abstraction opportunities.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests encapsulating requests as Command objects, but common_mistakes reveal retrofitting undo() is expensive, and making commands serializable for queuing requires changing from service references to value types. This typically involves creating command classes, handlers, and updating multiple call sites — a significant refactor within one domain area.

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

Closest to 'persistent productivity tax' (b5). The pattern applies across web, cli, and queue-worker contexts per applies_to. Once adopted, commands become a load-bearing abstraction — every new operation needs a command class, handler registration, and potentially queue/serialization considerations. It shapes how features are implemented without fully defining the system architecture.

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

Closest to 'notable trap' (t5). The misconception explicitly states developers wrongly believe Command is 'only useful for undo/redo functionality' when it actually enables queuing, logging, macro recording, and decoupling. This is a documented gotcha that most developers eventually learn through experience with command buses and CQRS discussions, but initial misunderstanding leads to either avoiding the pattern or implementing it without considering serialization and dependency injection requirements.

About DEBT scoring →

Also Known As

command object action pattern encapsulated request

TL;DR

Encapsulates a request as an object, enabling queuing, logging, undo/redo, and decoupling of request sender from receiver.

Explanation

The Command pattern wraps a request — with all its parameters — as an object implementing a common execute() interface. The invoker (controller, queue worker) knows only the Command interface; the receiver (domain service) knows nothing about the invoker. This enables: queuing and deferred execution, logging all executed commands for audit, undo/redo by implementing an unexecute() method, and macro commands (composites of commands). In PHP, the Command Bus pattern (used in CQRS frameworks like Tactician and Laravel's Command Bus) dispatches command objects to dedicated handler classes.

Common Misconception

The command pattern is only useful for undo/redo functionality. Commands also enable queuing, logging, macro recording, transactional operations, and decoupling the sender of a request from its executor.

Why It Matters

The Command pattern encapsulates a request as an object — enabling queuing, logging, undo/redo, and retry without coupling the invoker to the specific operation being performed.

Common Mistakes

  • Implementing Command without an undo() method when reversibility is a requirement — retrofitting it later is expensive.
  • Commands that access external services directly instead of through injected dependencies — makes testing hard.
  • Using a command bus for simple CRUD with no queue, audit, or retry requirement — overkill that adds complexity.
  • Not making commands serializable when they need to be queued or persisted — use value types, not service references.

Code Examples

✗ Vulnerable
// Direct invocation instead of command — no queuing, logging, or undo:
class OrderController {
    public function cancel(int $id): void {
        $order = Order::find($id);
        $order->status = 'cancelled'; // Logic scattered, no audit trail
        $order->save();
    }
}
✓ Fixed
interface Command {
    public function execute(): void;
    public function undo(): void;
}

class MoveFileCommand implements Command {
    public function __construct(
        private string $from,
        private string $to,
    ) {}
    public function execute(): void { rename($this->from, $this->to); }
    public function undo(): void    { rename($this->to, $this->from); }
}

class CommandHistory {
    private array $stack = [];
    public function execute(Command $cmd): void {
        $cmd->execute();
        $this->stack[] = $cmd;
    }
    public function undo(): void {
        array_pop($this->stack)?->undo();
    }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 29
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
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 1 ping T 0 pings W 2 pings T 1 ping F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 1 ping S
No pings yesterday
Amazonbot 9 Ahrefs 7 Perplexity 5 Google 2 Unknown AI 2 ChatGPT 2
crawler 25 crawler_json 2
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Encapsulate a request as a Command object with a handle() method — this enables queuing, logging, undo, and retry without changing the invoker
📦 Applies To
PHP 5.0+ web cli queue-worker laravel symfony
🔗 Prerequisites
🔍 Detection Hints
Action logic duplicated in controller and queue job; no reusable command object for the same operation
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant