[dev] Injector musings

Chuck Hagenbuch chuck at horde.org
Thu Feb 11 04:50:14 UTC 2010


Quoting Michael M Slusarz <slusarz at horde.org>:

> 1.) Is the eventual goal to remove all singleton methods from  
> libraries?  To me, the answer would seem to be yes because if we  
> eventually use getInstance()/createInstance() to reliably grab an  
> instance, if that library in the future would need an outside  
> dependency it would only be necessary to resolve this dependency by  
> creating a binder interface in Core.

Yes. I see no reason not to remove singletons and use the injector to  
manage number of instances.

> 2.) How do you create an instance with an injector if that  
> instance's constructor has varied arguments?  This seems to be a  
> limitation of Horde_Injector... is this by design or simply because  
> nobody has implemented it yet.

The latter, if I'm following. What I want to add to the injector (that  
came from a completely separate conversation with one of the folks who  
wrote the initial code) is setter injection. In the case of the  
Mime_Viewer objects, different viewers would have setFoo() methods for  
the dependencies that aren't in the constructor (common to all  
Mime_Viewers). The injector would then satisfy those dependencies as  
well on object creation.

> For example, Horde configuration needs to be decoupled from  
> Horde_Mime_Viewer.  However, every Horde_Mime_Viewer instance does  
> not need every single configuration option passed to it that might  
> potentially be used by the drivers.  On the other hand, the drivers  
> may create other Horde_Mime_Viewers internally that may need config  
> options not needed by the original driver.

For this last case the viewer should have a reference to the injector.  
Using setter injection this could be accomplished with a  
setInjector(Horde_Injector $injector) method; the injector would know  
to pass itself to this when creating the object.

> Regardless, it is very useful to keep the instance around since it  
> might be used elsewhere in the code.  A better example of this might  
> be IMP_Contents.  Once initialized, it may be used in various  
> locations around the code that are not accessible to each other.   
> How does this work with injector usage?  Or is this the motivation  
> to retain usage of singletons in this usage pattern?

I'm not sure I entirely follow the question. If the object  
instantiation/initialization is complicated, then a binder or factory  
for it seems appropriate. You can then call getInstance() wherever you  
need it, and the object will be created and initialized only once.

> 3.) Configuration buried deep within core library functions is  
> troublesome.  Example - Horde_Auth::setAuth(), which contains a call  
> to Net_DNS_Resolver, which may potentially be configured via Horde's  
> config file.  setAuth() is called from a variety of locations, and  
> is also called internally by a variety of other library calls.   
> Passing the resolver object as a parameter isn't really doable and  
> would be a giant step back in usability.  And it isn't possible to  
> pass the resolver object to Horde_Auth since it is not setup to be  
> OO for this kind of use.  Even if we convert to an OO-model,  
> Horde_Auth is called from so many places that if we have to add  
> additional parameters to 10's or 100's of calls, this seems like a  
> step back.

It seems like the static usage of Horde_Auth is a barrier here. If  
Horde_Auth were used non-statically then you could get a reference to  
it from the injector and then do what you needed without worrying  
about objects. We can also make things like the current username  
(getAuth) available as properties where appropriate so that they don't  
require accessing an object and a method call.

As an aside, I think one of the reasons there are potentially 100's of  
static Horde_Auth calls to worry about here is because of the kind of  
boilerplate code you've been arguing for removing/consolidating. In  
short: I agree. :)

At that point it doesn't seem unreasonable to pass the  
Net_DNS_Resolver object to Horde_Auth through either setter or  
constructor injection.

> My solution was to set a static public member variable to a  
> Net_DNS_Resolver object via the Horde_Registry.  It seems a bit  
> hackish, but also seems like the cleanest/easiest way to decouple  
> the configuration from the library.  Comments/concerns on this  
> approach is much appreciated.

Why not have a binder or factory to create the Net_DNS_Resolver  
object? I know this answer might not matter if Horde_Auth is still  
used statically, but see above.

-chuck


More information about the dev mailing list