From e27690055fdcf4896b1a11cdecec1de304c1cffc Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Fri, 3 Sep 2010 11:23:06 -0600 Subject: [PATCH] Add ondemand injector binders. Idea: Instead of instantiating a bunch of classes (which also requires, at least with autoloading, the corresponding file lookup/read) with no guarantee we will use a binder during a page access, create the binder from a static (string) class name when it is first requested. --- framework/Injector/lib/Horde/Injector.php | 55 ++++++++++++++++++++-- framework/Injector/package.xml | 2 +- .../Injector/test/Horde/Injector/InjectorTest.php | 8 ++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/framework/Injector/lib/Horde/Injector.php b/framework/Injector/lib/Horde/Injector.php index a147c036b..d4e93ac75 100644 --- a/framework/Injector/lib/Horde/Injector.php +++ b/framework/Injector/lib/Horde/Injector.php @@ -15,16 +15,29 @@ class Horde_Injector implements Horde_Injector_Scope { /** + * Parent scope. + * * @var Horde_Injector_Scope */ private $_parentInjector; /** + * Binders for objects/instances. + * * @var array */ private $_bindings = array(); /** + * Binders for objects/instances that are created on demand. + * + * @var array + */ + private $_ondemand = array(); + + /** + * Created objects/instances. + * * @var array */ private $_instances; @@ -107,7 +120,7 @@ class Horde_Injector implements Horde_Injector_Scope } /** - * Add a Horde_Injector_Binder to an interface + * Add a Horde_Injector_Binder to an interface. * * This is the method by which we bind an interface to a concrete * implentation or factory. For convenience, binders may be added by @@ -144,6 +157,39 @@ class Horde_Injector implements Horde_Injector_Scope } /** + * Add a Horde_Injector_Binder to an interface. Unlike addBinder(), the + * binder interface will not be created until it is first accessed. + * + * @see self::addBinder() + * + * @param string $interface The interface to bind to. + * @param string $name The name of the binder class to create. + * + * @return Horde_Injector A reference to itself for method chaining. + */ + public function addOndemandBinder($interface, $name) + { + $this->_ondemand[$interface] = $name; + return $this; + } + + /** + * Creates a binder object on demand from the current binder + * configuration. + * + * @param string $interface The interface to bind to. + */ + private function _addOndemandBinder($interface) + { + if (!isset($this->_bindings[$interface]) && + isset($this->_ondemand[$interface])) { + $binder = new $this->_ondemand[$interface](); + $this->_addBinder($interface, $binder); + unset($this->_ondemand[$interface]); + } + } + + /** * Get the Binder associated with the specified instance. * * Binders are objects responsible for binding a particular interface @@ -158,6 +204,8 @@ class Horde_Injector implements Horde_Injector_Scope */ public function getBinder($interface) { + $this->_addOndemandBinder($interface); + return isset($this->_bindings[$interface]) ? $this->_bindings[$interface] : $this->_parentInjector->getBinder($interface); @@ -237,14 +285,15 @@ class Horde_Injector implements Horde_Injector_Scope if (!isset($this->_instances[$interface])) { // Do we have a binding for this interface? If so then we don't // ask our parent - if (!isset($this->_bindings[$interface])) { + if (!isset($this->_bindings[$interface]) && + !isset($this->_ondemand[$interface])) { // Does our parent have an instance? if ($instance = $this->_parentInjector->getInstance($interface)) { return $instance; } } - // We have to make our own instance + // We have to make our own instance. $this->setInstance($interface, $this->createInstance($interface)); } diff --git a/framework/Injector/package.xml b/framework/Injector/package.xml index 3939df352..f4d8d10da 100644 --- a/framework/Injector/package.xml +++ b/framework/Injector/package.xml @@ -33,7 +33,7 @@ beta BSD - + * Add on-demand binders. * Initial release, contributed by Blue State Digital diff --git a/framework/Injector/test/Horde/Injector/InjectorTest.php b/framework/Injector/test/Horde/Injector/InjectorTest.php index b76958bdc..0ca0a1898 100644 --- a/framework/Injector/test/Horde/Injector/InjectorTest.php +++ b/framework/Injector/test/Horde/Injector/InjectorTest.php @@ -22,6 +22,14 @@ class Horde_Injector_InjectorTest extends PHPUnit_Framework_TestCase $this->assertSame($binder, $injector->getBinder('BOUND_INTERFACE')); } + public function testOndemandBoundBinder() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $binder = new Horde_Injector_Binder_Mock(); + $injector->addOndemandBinder('BOUND_INTERFACE', 'Horde_Injector_Binder_Mock'); + $this->assertNotSame($binder, $injector->getBinder('BOUND_INTERFACE')); + } + public function testShouldProvideMagicFactoryMethodForBinderAddition() { $injector = new Horde_Injector(new Horde_Injector_TopLevel()); -- 2.11.0