SitePoint Sponsor

User Tag List

Results 1 to 13 of 13
  1. #1
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Passing the Registry around

    Hi,
    I'm rolling my own small MVC framework, mostly in order to learn it and really get into OO, and I really feel like I've made some breakthroughs.

    I have a Registry-class which contains my most important instances, like Database and Request. But then I have an abstract Session-class and concrete SessionNative- and SessionDb-class. The SessionNative doesn't require any other classes to function, but the SessionDb-class needs a Database-instance to work. So I pass the Registry to all subclasses of Session, so it can decide itself what it needs from the Registry in order to work. It's working fine, but is it good practice? Is there something evil about sending the Registry around like this that I'm missing, or is it fine to do it like this? I could also make the Registry handle instantiation so I only need to change the Registry if classes need different arguments, but then I feel that the Registry would become bloated.

    Any thoughts?

  2. #2
    SitePoint Enthusiast
    Join Date
    Apr 2007
    Posts
    45
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think there is much problem with passing around the registry, as long as it's by reference and not by value! You could implement the registry as a Singleton meaning that any class can get at it from anywhere without having to pass it around.

    How do the database and request classes get a reference to the Registry in order to register themselves?

  3. #3
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you pass the registry, rather than the concrete dependency, you make it harder to spot the dependency. Therefore, you should favour passing the dependency, when you have the option.

    If your registry is instantiating objects, it's acting as a factory, and so should handle the full role of construction. This means putting information about concrete dependencies in there. You can prevent it from being bloated, by decoupling the factory for each class into a separate component. A simple solution could be a static function on the class, but to be really useful, the registry should allow a dynamic relationship to these factories. I prefer using a callback, but you could also use a more object oriented design.

  4. #4
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    tim912:
    Well, it is a Singleton, but I prefer not to call it's Singleton method, since static calls will make testing harder.

    kyber:
    Okay, so you're saying that basically every class that would be complex enough to need different objects should be instantiated in the Registry? I like the idea of the dynamic relationship, but how would that look like?

    Something like this?
    PHP Code:
    <?php
    class Registry
    {
        public function 
    __call$method$args )
        {
            
    $method preg_replace'/^get/'''$method );
            
    $factoryclass ucfirst$method ) . 'Factory';

            include( 
    $factoryclass '.class.php' );
            return 
    $factoryclass::getInstance$this );
        }
    }
    ?>
    But then I still pass the Registry to the factory, and let the factory decide what to do with it. But perhaps that's a good thing?

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    But then I still pass the Registry to the factory, and let the factory decide what to do with it. But perhaps that's a good thing?
    You really have three actors in here. There is the instance of the shared object, there is the class of it, and finally there is the factory for instantiating said object. If you do nothing special about it, the factory isn't a well defined component in your application -- It's partially handled by the constructor, and partially by the code calling the constructor.
    The first step is to encapsulate this in a static factory; this could be in the form of a function, or more commonly seen a static class method. Normally, the factory doubles as a container for the shared object. This is true of the singleton, and this holds true for most implementations of a registry+factory. There is two reasons for this; The first is that it sheilds the user from knowing if an instance is already instantiated -- The registry can simply call the factory transparently. This is also known as lazy loading, and is especially important in PHP. The other is that it allows the factory to ask the registry for other shared objects, which it might depend on.

    From a purist view, dynamic relationships are always preferable over static relationships. There is a slight cost in terms of complexity, but an added benefit in terms of decoupling. As your application matures, it will tend to replace static relationships with dynamic ones (Or become a spaghetti monster). Making your registry dynamic from the beginning is therefore a good idea. This means that you'll have to pass the registry around to anything which needs it. Further, you'd want to make relationship between registry and factories dynamic.

    Quote Originally Posted by wysiwyg View Post
    I like the idea of the dynamic relationship, but how would that look like?
    A na&#239;ve object oriented implementation could look something like this:
    PHP Code:
    <?php
    class MultiFactory
    {
      protected 
    $factories = Array();

      function 
    registerFactory($class$factory) {
        
    $this->factories[$class] = $factory;
      }

      function 
    newInstance($class$registry) {
        return 
    $this->factories[$class]->newInstance($class$registry);
      }
    }

    class 
    DefaultFactory
    {
      function 
    newInstance($class$registry) {
        return new 
    $class();
      }
    }

    class 
    Registry
    {
      protected 
    $instances = Array();
      public 
    $factory;
      
      function 
    __construct() {
        
    $this->factory = new MultiFactory();
      }
      
      function 
    get($class) {
        if (!isset(
    $this->instances[$class])) {
          
    $this->instances[$class] = $this->factory->newInstance($class$this);
        }
        return 
    $this->instances[$class];
      }
    }
    PHP Code:
    class Foo {}
    $reg = new Registry();
    $reg->registerFactory("Foo", new DefaultFactory());
    $foo $reg->get('Foo');
    $bar $reg->get('Foo');
    assert($foo === $bar); 
    You can see a fully working registry+factory at: http://svn.sourceforge.net/viewvc/ko...hp?view=markup. It's based on function-callbacks instead of object oriented factories, but the basic concept is the same. The function callback provides the dynamic.

  6. #6
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    30
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Another nice implementation is the one that is used by symfony.
    Create a parameter registry and construct new objects like:
    PHP Code:
    class SomeClass {
    var 
    $_parameters null;
    function 
    __construct($parameters = array())
    {
    $this->_parameters = new Parameter();
    $this->_parameters->add($parameters);

    The Parameter() class is a registry container, this adds great flexibility in extending your classes without the need of retouching the original code. Now all your classes extending the base one can access parameters through the $this->_parameter variable and you can construct them by simply passing an array to them.
    This eliminates the need to have a global registry getting passed as a reference or being called everytime you need something.

  7. #7
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, what's the difference between passing an array of parameters (objects) and passing the registry?

  8. #8
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    30
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    Well, what's the difference between passing an array of parameters (objects) and passing the registry?
    You implement a registry inside the parent class and then extensibility does need only to query the parameter container for the values needed. Instead of injecting all the time the registry.
    The registry is only local to the scope of the class (since you use a new Parameter call) and does not contain any kind of information from other classes.
    The parameters are not necessary objects, they could be simple plain parameters, this allows you to extend the base class without needing to modify the parent constructor if you subclass needs any other kind of parameters.
    So you make sure the parameters you pass (the array) do concern only the newly created class.

  9. #9
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > Well, what's the difference between passing an array of parameters (objects) and passing
    > the registry?

    If the Registry in question is an object, then your implementation has behaviour, whereas an array, which is a primitive type, has none

    PHP Code:
    // ...
    function __construct($parameters = array())
    {
    $this->_parameters = new Parameter();
    $this->_parameters->add($parameters);

    This may be ample enough for most purposes, however there are limitations; Why not just pass in Parameter it's self?

    That is what I do...

    PHP Code:
    // ...
    public function __constructQDataspace_Interface $dataspace ) {
    ... 
    In which case, I can easily just do this,

    PHP Code:
    $this -> import$dataspace );
    // ... 
    Which removes the dependency of Parameters from the concreate class altogether?

  10. #10
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    Well, what's the difference between passing an array of parameters (objects) and passing the registry?
    I don't see the point either. I tried browsing the documentation for Symfony, to see if I could figure it out, but there's no class Parameter (Or I can't find it). pestilence_gr -- Can you point to the place in the source, where this happens?

  11. #11
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    30
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    I don't see the point either. I tried browsing the documentation for Symfony, to see if I could figure it out, but there's no class Parameter (Or I can't find it). pestilence_gr -- Can you point to the place in the source, where this happens?
    http://www.symfony-project.com/book/...eter%20Holders
    Just scroll a bit down (seems the anchor is not placed correctly)

  12. #12
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pestilence_gr View Post
    http://www.symfony-project.com/book/...eter%20Holders
    Just scroll a bit down (seems the anchor is not placed correctly)
    Thanks. So what I get from this is, that the ParameterHolder is basically an array, implemented as an object with methods. Back when we had PHP4, some people (myself inclusive) used a generic DataSpace interface, to allow different objects to act uniformly. The real advantage of this approach was, that you could wrap a primitive array in it, and thus let arrays and objects work interchangeably. With PHP5, I don't see the need, since you can use the SPL classes on the few occasions, where you need a primitive array to be interchangeable with an object.

    So basically, the ParameterHolder is an ArrayObject, which is used to provide the registry pattern.

    In the constructor, the contents of the ParameterHolder is imported into a local instance of it. I don't really see why what this would archieve. The following would be simpler, I think:

    PHP Code:
    ...
    function 
    __construct($parameters) {
      
    $this->_parameters $parameters;

    At this point, there is no difference between that, and the thing, I call a registry. There seems to be no consensus on the naming anyway, so parameters may be just as good.

    A thing that strikes me about this, is that it encourages passing the registry, rather than the dependencies. While not a big problem, I would say that it is a bad practice. It's much easier to read the code, if dependencies are passed explicitly, and furthermore it decouples the registry from the consumer (The object, in need of dependencies).

  13. #13
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    30
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh I forgot to mention I found interesting the idea (and actually just implemented it today) of a static Conf registry with a lock mechanism.
    I did load the configuration in the registry and then applyed a setLock method to set a static var to true ( $lock = true) all the setter methods must make a check first to the $lock var, if its true (which means locked) it wont allow a new var to be set.
    This is not much but it will help you prevent users accidentaly overwritting a conf var or loading additional data (that could be implemented in another registry type).


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •