-
Notifications
You must be signed in to change notification settings - Fork 0
Usage
Singleton ensures that only a single instance of a class exists per application.
By using the trait FlorianWolters\Component\Util\Singleton\SingletonTrait
, a class implements the Singleton creational design pattern.
The following Factory Method (to create logger instances) demonstrates this. Factory Methods are a good example for the usage of the Singleton design pattern (whereas a database connection is a bad example).
<?php
namespace FlorianWolters\Component\Util\Log;
use \InvalidArgumentException;
use FlorianWolters\Component\Util\Singleton\SingletonTrait;
use Psr\Log\LoggerInterface;
class LoggerFactory
{
use SingletonTrait;
/*
* Constructs a new logger.
*
* @param string $type The type of the logger to create.
*
* @return LoggerInterface The logger instance.
*/
public function createLogger($type = 'echo')
{
/* @var $result Psr\Log\LoggerInterface */
$result = null;
switch ($type) {
case 'echo':
// A logger implementation may also be a Singleton or Multiton.
$result = EchoLogger::getInstance();
break;
case 'null':
$result = NullLogger::getInstance();
break;
default:
InvalidArgumentException('The given logger type is invalid.');
break;
}
return $result;
}
}
The following source code demonstrates the usage of the class LoggerFactory
.
<?php
$nullLogger = LoggerFactory::getInstance('null');
$nullLogger->info('foo');
The Singleton implementation of the trait FlorianWolters\Component\Util\Singleton\SingletonTrait
disallows creating (via the method __construct
), cloning (via the method __clone
) and unserializing (via the method __wakeup
) of a Singleton instance.
<?php
$loggerFactory = LoggerFactory::getInstance(); // OK
$serializedLoggerFactory = \serialize($loggerFactory); // OK
\unserialize($serializedLoggerFactory); // E_WARNING: Invalid callback FlorianWolters\Component\Util\Log\LoggerFactory::__wakeup, cannot access private method FlorianWolters\Component\Util\Log\LoggerFactory::__wakeup() in [...] on line [...]
clone $loggerFactory; // E_ERROR: Call to private LoggerFactory::__clone() from invalid context in [...] on line [...]
new LoggerFactory; // E_ERROR: Call to protected LoggerFactory::__construct() from invalid context in [...] on line [...]
Multiton (a.k.a. Registry of Singletons) is a variation of the Singleton design pattern.
It expands the Singleton concept to manage a map of named instances as key-value pairs. In contrast to Singleton, Multiton ensures that only a single instance of a class exists per key. All other constraints of Singleton do also apply for Multiton.
By using the trait FlorianWolters\Component\Util\Singleton\MultitonTrait
, a class implements the Multiton creational design pattern.
The following Value Object (which models a simple user) demonstrates this.
<?php
namespace FlorianWolters\Component\Model;
use FlorianWolters\Component\Util\Singleton\MultitonTrait;
class UserModel
{
use MultitonTrait;
private $username;
private $password;
protected function __construct($username, $password)
{
$this->username = $username;
$this->password = $password;
}
public function getUsername()
{
return $this->username;
}
public function getPassword()
{
return $this->password;
}
}
The following usage example for the class UserModel
demonstrates the passing of arguments to the protected constructor of the class via the static Creational Method getInstance
.
<?php
$user = UserModel::getInstance('john_doe', '1234');
$user->getUsername(); // 'john_doe'
$user->getPassword(); // '1234'
A new instance of a Multiton is created, if the arguments of the static Creational Method getInstance
differ.
<?php
$userJohn = UserModel::getInstance('john_doe', '1234');
$userJane = UserModel::getInstance('jane_doe', 'test');
\var_dump($userJohn === $userJane); // false
\var_dump(UserModel::getInstance('john_doe', '1234') === $userJohn); // true
\var_dump(UserModel::getInstance('jane_doe', 'test') === $userJane); // true
The following calls will fail with a PHP error:
<?php
new UserModel('john_doe', '1234'); // E_ERROR: Call to protected UserModel::__construct() from invalid context in [...] on line [...]
UserModel::getInstance('john_doe'); // E_WARNING: Missing argument 2 for UserModel::__construct() in [...] on line [...]