-- Robert Basic <[email protected]> wrote
(on Monday, 17 September 2012, 04:33 PM +0200):
> I'm writing my first ZF2 controller, and am wondering about accessing
> other objects (models, services...) in a controller. As I see it now,
> there are 2 ways to do this, and both ways seem perfectly fine to
> me... But maybe I'm missing something I don't see, and in the long
> run, one way is better than the other.
> 
> One way is by injecting the dependencies like this:
> https://github.com/akrabat/zf2-tutorial/blob/master/module/Album/Module.php#L23
> and then the controller has the setAlbumTable method, etc...
> 
> The other way is by configuring the service locator/manager/whatever
> it's called, and then getting the object in the controller via
> $this->getServiceLocator()->get('album-table') ...
> 
> Personally, I'm leaning towards the second way:
>  - I know that the object is being called from the service locator
>  - As long as the called object implements the
> ServiceLocatorAwareInterface, it gets the service locator injected
> (this maybe happens with the first way too, don't know, haven't
> checked.)
>  - From the unit tests PoV, it's... the same. Well, almost, the second
> way requires a bit more configuring of the service locator in the
> tests, but other than that, can't see any other difference. You'll
> need to configure the SL for the first way too, if you want to access
> the controller plugin manager/controller plugins.
>  - My brain reads it/parses it/understands it easier.
> 
> So, is my brain completely wrong and the first way is better, or am I
> correct going with the second option? Or maybe in the end it doesn't
> matter, as it boils down to the same? OR, is it on a case-by-case
> basis?

I personally have been recommending the first way. The primary reasons
are:

 * It makes your code self-documenting. You can look at API docs of your
   classes, and know immediately what dependencies they have.

   If you instead inject a Service Locator, and pull objects from that,
   it's anybody's guess what dependencies are needed unless you scan the
   code itself. The only hard dependency is on the Service Locator --
   which is at best a mediator between your class and the objects it
   consumes.

 * It makes substitutions easier. Want to see if a different service
   that provides the same implementations can work? Modify the factory
   quickly, and test. This is harder when you use a Service Locator
   inside your class, as you're also hard-coding the service name within
   your code. With a factory, the consuming code is de-coupled from the
   service name.

 * As you noted, it makes testing easier. You can look at the factory
   you use in your application to get an idea of how to construct the
   object, and then simply re-create that in your test setup. If you
   rely on a service locator, you have to look through your code to see
   what services are pulled from it, which is extra effort.

Basically, it's the difference between using a registry, and using an
Inversion of Control (IoC) container. Registries are easy, fast, and
seductive, but have side effects (undocumented dependencies,
dependencies updated by other classes elsewhere, etc.); IoC containers
require you to flip your thinking around, but make the code
self-documenting, and dependencies easier to identify and provide
substitutions for.

We _do_ use the ServiceLocatorAwareInterface within the framework. I was
loathe to add it to the controllers by default, but did so primarily to
enable plugins access to workflow-related objects (look at the url() and
forward() plugins for examples). Otherwise, I highly recommend passing
your dependencies _to_ your objects, rather than fetching them _from_
the SL.

-- 
Matthew Weier O'Phinney
Project Lead            | [email protected]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc

-- 
List: [email protected]
Info: http://framework.zend.com/archives
Unsubscribe: [email protected]


Reply via email to