-- 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]
