Explain the Singleton design pattern in PHP.
The Singleton Design Pattern in PHP is a creational pattern that ensures:
- Only one instance of a class exists during the lifetime of the application.
- That instance is globally accessible.
This is useful when you want a single point of access to a resourceβlike a database connection, logger, or configuration manager.
Key Concepts
- Private constructor β Prevents creating new objects from outside.
- Static property β Stores the single instance.
- Public static method β Provides global access to the instance.
- Private clone method β Prevents cloning of the instance.
- Private wakeup method β Prevents unserialization.
Example: Singleton for Database Connection
<?php
class Database {
private static $instance = null; // Holds the single instance
private $connection;
// Private constructor so no one can instantiate directly
private function __construct() {
$this->connection = new mysqli("localhost", "root", "", "test_db");
if ($this->connection->connect_error) {
die("Database connection failed: " . $this->connection->connect_error);
}
}
// Prevent cloning
private function __clone() {}
// Prevent unserializing
private function __wakeup() {}
// Access method to get the single instance
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// Method to get the connection
public function getConnection() {
return $this->connection;
}
}
// Usage
$db1 = Database::getInstance();
$db2 = Database::getInstance();
if ($db1 === $db2) {
echo "Same instance of database connection";
}
?>
How it works
Database::getInstance()checks if an instance already exists.- If not, it creates one and stores it in
self::$instance. - All calls to
getInstance()return the same object. private __clone()andprivate __wakeup()ensure no copies are made.
Advantages
β
Saves memory and resources (only one object is created).
β
Centralized control over the instance.
β
Good for managing shared resources like configuration or logging.
Disadvantages
β Can introduce global state (harder to test in unit tests).
β Overused in wrong contexts can lead to tight coupling.
Letβs take a real-world PHP example of the Singleton design pattern:
Weβll use a Logger class that writes logs to a file.
In many applications, you want a single logging instance so all parts of the app write to the same file without creating multiple file handlers.
Real-World Example: Logger
<?php
class Logger {
private static $instance = null;
private $fileHandle;
// Private constructor to prevent direct creation
private function __construct() {
$logFile = __DIR__ . "/app.log";
$this->fileHandle = fopen($logFile, "a");
if (!$this->fileHandle) {
throw new Exception("Could not open log file.");
}
}
// Prevent cloning
private function __clone() {}
// Prevent unserializing
private function __wakeup() {}
// Get the single instance
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// Write message to log file
public function log($message) {
$time = date("Y-m-d H:i:s");
fwrite($this->fileHandle, "[$time] $message" . PHP_EOL);
}
// Close file handle on object destruction
public function __destruct() {
fclose($this->fileHandle);
}
}
// Usage Example:
$logger1 = Logger::getInstance();
$logger1->log("User logged in.");
$logger2 = Logger::getInstance();
$logger2->log("User updated profile.");
// Both $logger1 and $logger2 are the same instance
if ($logger1 === $logger2) {
echo "Only one logger instance is being used.";
}
?>
Where you can use this in PHP projects
- Database Connection Manager (most common)
- Logging System (like above)
- Configuration Loader (load config once, use everywhere)
- Caching Manager (e.g., Redis or Memcached handler)
- Session Manager (centralized session handling)
