Singleton (Anti-Pattern)
Also Known As
singleton pattern
single instance
global instance
TL;DR
A class that restricts instantiation to a single instance — widely considered an anti-pattern due to hidden global state and testability issues.
Explanation
The Singleton pattern guarantees only one instance of a class exists and provides a global access point. While it solves real problems (single database connection, single logger), it introduces global state that makes classes dependent on Singleton internals, complicates testing (can't substitute mock implementations easily), and violates Dependency Inversion. The preferred alternative is using a Dependency Injection container to manage instance lifetime — register services as shared/singleton in the container, inject them via constructors.
Common Misconception
✗ Singletons are a clean way to share a single instance across an application. Singletons are global state disguised as a pattern — they make unit testing nearly impossible (the instance persists between tests), hide dependencies, and create tight coupling. Dependency injection achieves the same single-instance goal without these problems.
Why It Matters
The Singleton pattern ensures one instance of a class exists globally — but it creates hidden global state that makes testing difficult and couples code to a specific implementation.
Common Mistakes
- Using Singleton for services that should be injected — it prevents swapping implementations in tests.
- Singleton that is not thread-safe in async or multi-process contexts.
- Singletons that accumulate state across tests — tests must reset singleton state to be isolated.
- Using Singleton when dependency injection containers already manage instance lifetime.
Code Examples
💡 Note
The Singleton itself isn't the problem — global mutable state is. Let a DI container manage instance lifetime instead.
✗ Vulnerable
class Config {
private static ?self $instance = null;
private function __construct() {}
public static function getInstance(): self {
self::$instance ??= new self();
return self::$instance;
}
// Testing is impossible — can't inject a different Config
// Shared mutable state across the application
}
✓ Fixed
// Use DI container to manage single instance instead
// config/app.php (Laravel service container)
$app->singleton(Config::class, fn() => new Config(getenv('APP_ENV')));
// Injected wherever needed — mockable in tests
class AppController {
public function __construct(private Config $config) {}
}
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
20
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
ChatGPT 4
Unknown AI 3
Google 3
Ahrefs 2
Perplexity 1
Also referenced
How they use it
crawler 10
crawler_json 2
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: High
⚡ Quick Fix
Replace Singletons with dependency injection — a DI container can manage single instances without the global state problem; Singleton makes testing impossible because you can't swap the instance
📦 Applies To
any
web
cli
queue-worker
🔗 Prerequisites
🔍 Detection Hints
getInstance() static method; private constructor with static $instance; global state via Singleton breaking test isolation
Auto-detectable:
✓ Yes
phpstan
phpmd
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: High
Context: Class
Tests: Update