2.5. Singleton¶
2.5.1. Intent¶
The purpose of the Singleton pattern is to ensure that a class will only have one instance at any time during code execution. Another key feature is to provide a global access to that instance.
2.5.2. When to use it?¶
For many people (including myself), Singleton is the political and nice name for global variables on object-oriented programming and that is the main drawback (global access + global state).
Global access makes source code hard to test ! Indeed, each objects should declare its collaborators in the constructor (dependency injection) in order to be able to mock dependencies.
For more details, I suggest you the great Miško Hevery’s blog (The Testability Explorer) and especially these posts:
Having said this, a few Singletons may be used inside your application without “harming” it. All objects that do not affect the behavior of your application (like a Logger) may be perfect examples.
2.5.3. Diagram¶
Created using PhpStorm and yFiles.
2.5.4. Implementation¶
Logger.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php
namespace Phpatterns\Creational\Singleton;
/**
* Logger used as a Singleton
*
* 'final' keyword used to prevent from creating subclasses (be sure to keep only one instance of the Logger)
*
*/
final class Logger
{
private static $instance = null;
/**
* Creates the Logger instance at the first call and then always returns
* the same instance
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self;
}
return self::$instance;
}
/**
* Prevent from creating object directly
*/
private function __construct()
{
}
/**
* Prevent from cloning object
*/
private function __clone()
{
}
/**
* Prevent from being serialized
*/
private function __sleep()
{
}
/**
* Prevent from being unserialized
*/
private function __wakeup()
{
}
}
|
2.5.5. Tests¶
LoggerTest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php
namespace Test\Phpatterns\Creational\Singleton;
use Phpatterns\Creational\Singleton\Logger;
class LoggerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \ReflectionObject
*/
private $reflectionObject;
protected function setUp()
{
$this->reflectionObject = new \ReflectionObject(
Logger::getInstance()
);
}
/**
* Assert that 2 Logger instances are equal
*/
public function testSingleton()
{
$logger1 = Logger::getInstance();
$logger2 = Logger::getInstance();
$this->assertSame($logger1, $logger2);
}
/**
* @param string $method
* @dataProvider methodProvider
*/
public function testPrivateMethods($method)
{
$reflectionMethod = $this->reflectionObject->getMethod($method);
$this->assertTrue($reflectionMethod->isPrivate());
}
public function methodProvider()
{
return [
['__construct'],
['__clone'],
['__sleep'],
['__wakeup']
];
}
}
|