Programming Languages PHP Subjective
Sep 23, 2025

Implement a thread-safe singleton pattern in PHP using modern techniques. Discuss the challenges and alternatives.

Detailed Explanation

Thread-Safe Singleton Implementation:

final class DatabaseConnection {
    private static ?self $instance = null;
    private static object $lock;
    private PDO $connection;
    
    private function __construct() {
        // Initialize lock object for thread safety
        if (!isset(self::$lock)) {
            self::$lock = new stdClass();
        }
        
        $this->connection = new PDO(
            "mysql:host=localhost;dbname=app",
            "user", "password",
            [PDO::ATTR_PERSISTENT => true]
        );
    }
    
    public static function getInstance(): self {
        if (self::$instance === null) {
            // Double-checked locking pattern
            synchronized(self::$lock, function() {
                if (self::$instance === null) {
                    self::$instance = new self();
                }
            });
        }
        return self::$instance;
    }
    
    public function getConnection(): PDO {
        return $this->connection;
    }
    
    // Prevent cloning and unserialization
    private function __clone() {}
    private function __wakeup() {}
    public function __serialize(): array {
        throw new Exception("Singleton cannot be serialized");
    }
}

Modern Alternative - Dependency Injection:

// Service Container Approach
class Container {
    private array $services = [];
    private array $singletons = [];
    
    public function singleton(string $abstract, callable $factory): void {
        $this->services[$abstract] = $factory;
        $this->singletons[$abstract] = true;
    }
    
    public function get(string $abstract): mixed {
        if (isset($this->singletons[$abstract])) {
            static $instances = [];
            return $instances[$abstract] ??= $this->services[$abstract]();
        }
        
        return $this->services[$abstract]();
    }
}

// Usage
$container = new Container();
$container->singleton(DatabaseConnection::class, fn() => new DatabaseConnection());

// Thread-safe through container
$db = $container->get(DatabaseConnection::class);

Challenges with Singleton:

  • Testing: Difficult to mock and test
  • Thread Safety: Requires synchronization in multi-threaded environments
  • Global State: Creates hidden dependencies
  • Scalability: Can become bottleneck in high-concurrency applications

Better Alternatives:

  • Dependency Injection: More testable and flexible
  • Service Locator: Centralized service management
  • Factory Pattern: Better control over object creation
  • Connection Pooling: For database connections specifically
Discussion (0)

No comments yet. Be the first to share your thoughts!

Share Your Thoughts
Feedback