diff --git a/core/Object.php b/core/Object.php index 72b5903cf..3031f716f 100755 --- a/core/Object.php +++ b/core/Object.php @@ -142,6 +142,27 @@ abstract class Object { return Injector::inst()->createWithArgs($class, $args); } + /** + * Creates a class instance by the "singleton" design pattern. + * It will always return the same instance for this class, + * which can be used for performance reasons and as a simple + * way to access instance methods which don't rely on instance + * data (e.g. the custom SilverStripe static handling). + * + * @param string $className Optional classname (if called on Object directly) + * @return static The singleton instance + */ + public static function singleton() { + $args = func_get_args(); + + // Singleton to create should be the calling class if not Object, + // otherwise the first parameter + $class = get_called_class(); + if($class === 'Object') $class = array_shift($args); + + return Injector::inst()->get($class); + } + private static $_cache_inst_args = array(); /** diff --git a/docs/en/changelogs/3.2.0.md b/docs/en/changelogs/3.2.0.md index e2524a987..dbd0f30e5 100644 --- a/docs/en/changelogs/3.2.0.md +++ b/docs/en/changelogs/3.2.0.md @@ -36,6 +36,7 @@ * `SQLConditionalExpression/SQLQuery` `select()`, `limit()`, `orderby()`, `groupby()`, `having()`, `from()`, `leftjoin()`, `innerjoin()`, `where()` and `whereAny()` removed. Use `set*()` and `add*()` methods instead. * Template `<% control $MyList %>` syntax removed. Use `<% loop $MyList %>` instead. + * Object::singleton() method for better type-friendly singleton generation ### CMS diff --git a/tests/core/ObjectTest.php b/tests/core/ObjectTest.php index 31dc44947..6f745b2ad 100644 --- a/tests/core/ObjectTest.php +++ b/tests/core/ObjectTest.php @@ -150,6 +150,16 @@ class ObjectTest extends SapphireTest { $this->assertTrue($obj3_2 instanceof ObjectTest_CreateTest3); } + /** + * Tests {@link Object::singleton()} + */ + public function testSingleton() { + $inst = Controller::singleton(); + $this->assertInstanceOf('Controller', $inst); + $inst2 = Controller::singleton(); + $this->assertSame($inst2, $inst); + } + public function testGetExtensions() { $this->assertEquals( Object::get_extensions('ObjectTest_ExtensionTest'),