views:

548

answers:

3

Do you find Zend_Registry useful?

For which tasks it should be used? For which not?

Global state for variables is not a good practice. Main objects may have global state injected via $front->setParam('paramName', $object), so what's the purpose of Zend_Registry?.

+3  A: 

Quoting PoEAA on Registry Pattern:

When you want to find an object you usually start with another object that has an association to it, and use the association to navigate to it. Thus, if you want to find all the orders for a customer, you start with the customer object and use a method on it to get the orders. However, in some cases you won't have an appropriate object to start with. You may know the customer's ID number but not have a reference. In this case you need some kind of lookup method - a finder - but the question remains: How do you get to the finder?

The main reason why I use the registry (when I use it) is because it creates an easily accessible application scope. With the registry, I don't have to litter objects all over the global scope; only the Registry itself is global. It's convenient to lookup whatever I've thrown into the Registry from everywhere, including the model:

  • Zend_Cache, Zend_Translate, important applications paths, etc

However, just like with Singletons, Registry is often frowned upon. Here is an article by Brandon Savage with some thought about why not to use the Registry. The main arguments against the Registry are

  • it makes unit-testing harder
  • inexperienced coders might throw too much into it and don't care about proper design

Those who vote against the Registry usually advocate the usage of Dependency Injection, although it should be noted that you can inject the Registry as well once you got an instance of it. You do not have Inversion of Control then though, because the using object will pull what it needs from the Registry. Using the Registry as a Service Locator is a valid approach though.

See this article by Martin Fowler about ServiceLocator vs. Dependency Injection.

Like pointed out in the comments to your question, Zend_Registry is not a strict Singleton. You can instantiate multiple instances where needed in addition to using the global instance you get with Zend_Registry::getInstance(). So objects can have their own registry. But when using Registry this way, it's basically just a glorified ArrayObject.

Final note: just like with all Design Patterns, use it if applicable to your problem.

Gordon
+6  A: 

When you are using $front->setParam, you are defining a parameter in the Front Controller.

But that parameter is not available in (or should not be used from) other layers of the application, such as the Model.

Zend_Registry, like any other global variable, is available from anywhere in your application -- including inside the Model.

But using a Registry instead of a bunch of global variables ensures you won't have many global variables everywhere : even if using a Registry implies some global state (which is not that good, one should say), it's better to have that all in one place.


A couple of real life examples could be :

  • Store the connection to the database, which is established in the bootsreap, but used in the Models
  • Globally store an adapter (or any mecanism) that will be used to do translations / localisation in all layers of your application -- Zend Framework itself does that.


In the end, do I find Zend_Registry useful ?

Well, when it comes to having some global state, yes, it's useful.

But if it's usage can be avoided, it might be better : conceptually speaking, not having your classes depend on any global state is better : easier to re-use, easier to test, ...
About that, you might want to take a look at what Dependency Injection is.

Pascal MARTIN
Isn't $front->setParam the dependency injection? What about the Zend Application Resources?
takeshin
+1  A: 

I agree with Pascal MARTIN. I just started accustoming myself to Dependency Injection. But I haven't found a way to inject objects in controllers, so what I recently did was use de registry to access a service in the controller. In a current project I'm doing the following:

bootstrap:

// simple DI without an IoC container, and what have you
$dbAdapter    = Zend_Db::factory( /* bla bla */ );
$mediaService = new Service_Media( new Repository_Media_Db( $dbAdapter ) );
$registry     = Zend_Registry::getInstance();
$registry->mediaService = $mediaService;

...then in a controller:

public function init()
{
    $this->_mediaService = Zend_Registry::get( 'mediaService' );
}

public function listAction()
{
    // simplified
    $this->view->media = $this->_mediaService->listAllUploadedVideos();
}

Hopefully this is a useful example for you.

fireeyedboy
Is registry really needed here? Action helper wouldn't be enough?
takeshin
What I usually do: _initMediaService(){return $service;};, then in the action controller: $front->getParam('mediaService');
takeshin
Action helper is a good option too I guess. That is... as long as it's only needed in a controller. But you might have a situation where this service is needed in another service or business layer too. Although that could be taken care of by constructor injection again I guess. Hmm.. I haven't really thought about it in too much depth yet as you can see. So far this example suits my purposes. I guess there are lot's of ways to accomplish a task. It all depends on how much of a purists approach you wanna take I guess. As soon as I digg into DI a bit more, I'll probably ditch this approach.
fireeyedboy
As for your second comment; I haven't gotten around to the new OOP bootstrap approach yet either (still using procedural bootstrap). But I assume, from your example, that an _init method automatically assigns the return value to a param in the front controller? This could be an option. But like Pascal mentioned, and as per my previous comment, you shouldn't use this in other layers except your controllers (and view helpers perhaps). You don't want to tie your business layers to the front controller. They don't have any business knowing about the front controller.
fireeyedboy