Design Patterns In Action: The Singleton

The Singleton design pattern is used to restrict the instantiation of a class to a single instance. Useful in situations where only one instance of a class is needed throughout the execution of your app. In other words, it ensures a class has only one instance, while providing a global access point to this instance. An example of the Singleton pattern in action using PHP might be something like a message handling class that stores various types of messages.:

class MessageHandler
{
    private static $instance;
    private $successMessages = [];
    private $errorMessages = [];
    private $warningMessages = [];
    private $infoMessages = [];

    private function __construct() {}

    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    public static function success($message)
    {
        static::getInstance()->successMessages[] = $message;
    }

    public static function error($message)
    {
        static::getInstance()->errorMessages[] = $message;
    }

    public static function warning($message)
    {
        static::getInstance()->warningMessages[] = $message;
    }

    public static function info($message)
    {
        static::getInstance()->infoMessages[] = $message;
    }

    public static function getSuccessMessages() {
        return static::getInstance()->successMessages;
    }

    public static function getErrorMessages() {
        return static::getInstance()->errorMessages;
    }

    public static function getWarningMessages() {
        return static::getInstance()->warningMessages;
    }

    public static function getInfoMessages() {
        return static::getInstance()->infoMessages;
    }
}

Example usage:

// Store messages
MessageHandler::success("The operation was successful");
MessageHandler::warning("This is a warning message");
MessageHandler::info("This is an informative message");
MessageHandler::error("The operation failed");

// Retrieve messages
$successMessages = MessageHandler::getSuccessMessages();
$warningMessages = MessageHandler::getWarningMessages();
$infoMessages = MessageHandler::getInfoMessages();
$errorMessages = MessageHandler::getErrorMessages();

If we plan of having a multitude of message types, or we just want to clean up the class a bit, we could modify it so that it doesn’t concern itself with the type of message. This will keep us going SOLID with the single responsibility principle as well as save us some lines of code. Here is the revised class:

class MessageHandler
{
    private static $instance;
    private $messages = [];

    private function __construct() {}

    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    public static function addMessage($type, $message)
    {
        static::getInstance()->messages[$type][] = $message;
    }

    public static function getMessages($type) {
        $messages = static::getInstance()->messages[$type] ?? [];
        static::getInstance()->messages[$type] = [];
        return $messages;
    }
}

Example usage:

// Store the usual messages
MessageHandler::addMessage("success", "The operation was successful");
MessageHandler::addMessage("warning", "This is a warning message");
MessageHandler::addMessage("info", "This is an informative message");
MessageHandler::addMessage("error", "The operation failed");

// And some new types of messages
MessageHandler::addMessage("critical", "This is a critical message");
MessageHandler::addMessage("dev", "This is a dev message");

// Retrieve the messages
$successMessages = MessageHandler::getMessages("success");
$warningMessages = MessageHandler::getMessages("warning");
$infoMessages = MessageHandler::getMessages("info");
$errorMessages = MessageHandler::getMessages("error");
$criticalMessages = MessageHandler::getMessages("critical");
$devMessages = MessageHandler::getMessages("dev");

On a side-note, if you’re looking for a flash type system that persists the messages to the next page request, you could implement the above using session data. In fact, Laravel has a flash helper to do just that.

Related Posts