Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New features for Singleton object #53

Open
wants to merge 1 commit into
base: threads
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion src/eTools/Utils/Singleton.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,53 @@ abstract class Singleton {

protected static $instances = array();

private static $override_instances = array();

/**
* Returns a singleton object of a given class. Extend this class, then call \YourClass::getInstance() from anywhere
* in the application.
*
* If an override class is registered, that will be returned instead. Thi
*
* @return \stdClass A singleton of the requested class
*/
public static function getInstance() {
$class = get_called_class();
$args = func_get_args();

// Check if an override is set, and replace the class name to load if it is
if (isset(self::$override_instances[$class])) {
$class = self::$override_instances[$class];
}

// Create a singleton instance of the class if it doesn't already exist
if (!isset(self::$instances[$class])) {
self::$instances[$class] = new $class();
if(is_array($args) && sizeof($args) > 0) {
$reflectionClass = new \ReflectionClass($class);
self::$instances[$class] = $reflectionClass->newInstanceArgs($args);
} else {
self::$instances[$class] = new $class();
}
}

return self::$instances[$class];
}

/**
* Configures an override class, that can later be returned by self::getInstance().
*
* @param string $oldClass The class name to replace
* @param string $newClass The class to replace this with
* @return void
*/
public static function set_override_instance($oldClass, $newClass) {
self::$override_instances[$oldClass] = $newClass;
}

public static function clear_instances() {
self::$instances = array();
}

protected function __construct() {

}
Expand Down
91 changes: 91 additions & 0 deletions tests/eTools/Utils/SingletonTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
namespace eTools\Tests\Utils;

use eTools\Utils\Singleton;

class SingletonTest extends \PHPUnit_Framework_TestCase {
public function setUp() {
Singleton::clear_instances();
}

/**
* This tests ensures that the Singleton::getInstance() method always returns the same object every time you call it
*/
public function testGetInstance() {
/** @var SingletonSubclass $obj */
$obj = SingletonSubclass::getInstance();
$this->assertEquals(false, $obj->getCheck());
$obj->toggleCheck();

/** @var SingletonSubclass $obj2 */
$obj2 = SingletonSubclass::getInstance();
$this->assertEquals(true, $obj2->getCheck());

$obj2->toggleCheck();
$this->assertEquals(false, $obj->getCheck());
}

public function testGetInstanceSetsConstructorArgs() {
/** @var SingletonSubclass $obj */
$obj = SingletonSubclass::getInstance('arg1', 'arg2');
$this->assertEquals('arg1', $obj->getConstructorArg1());
$this->assertEquals('arg2', $obj->getConstructorArg2());
}

/**
* This test ensures that the Singleton::set_override_instance() method overrides classes correctly
*/
public function testOverrideInstances() {
// Before setting an override, we should get the normal class
$singletonSubclass = SingletonSubclass::getInstance();
$this->assertInstanceOf('eTools\Tests\Utils\SingletonSubclass', $singletonSubclass);

// Set the override and try again, we should now get the overridden method
Singleton::set_override_instance(
'eTools\Tests\Utils\SingletonSubclass',
'eTools\Tests\Utils\SingletonOverrideSubclass'
);

// Ensure it hasn't changed the existing instance somehow
$this->assertInstanceOf('eTools\Tests\Utils\SingletonSubclass', $singletonSubclass);
$this->assertInstanceOf('eTools\Tests\Utils\SingletonOverrideSubclass', SingletonSubclass::getInstance());

// Ensure override works every time once it's set
$this->assertInstanceOf('eTools\Tests\Utils\SingletonOverrideSubclass', SingletonSubclass::getInstance());
}
}

/**
* Class SingletonSubclass
* @package eTools\Tests\Utils
*
* This is a sample class - it should be used only for testing
*/
class SingletonSubclass extends Singleton {
private $check = false;
private $constructorArg1 = null;
private $constructorArg2 = null;

public function __construct($arg1 = null, $arg2 = null) {
$this->constructorArg1 = $arg1;
$this->constructorArg2 = $arg2;
}

public function toggleCheck() {
$this->check = !$this->check;
}

public function getCheck() {
return $this->check;
}

public function getConstructorArg1() {
return $this->constructorArg1;
}

public function getConstructorArg2() {
return $this->constructorArg2;
}
}

class SingletonOverrideSubclass extends Singleton {}