SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    344
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)

    Designing a framework without using static variables or methods

    Is it even possible? And how difficult can it be? Just wondering, I know that Dependency Injection can solve this problem for a smaller system, but in larger systems you have to pass 5+ dependent objects in the constructor this can be a messy work. How about Dependency Injector(Container)? Is it gonna help in this situation?

  2. #2
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,156
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    It's totally doable. In fact, I believe that the more modern codebases such as Symfony and Zend are already largely instance-based. The messiness of dependency injection is typically hidden away with a dependency injection container.

    If you have a more specific scenario, I can try to give a more specific answer.
    "First make it work. Then make it better."

  3. #3
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    344
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    It's totally doable. In fact, I believe that the more modern codebases such as Symfony and Zend are already largely instance-based. The messiness of dependency injection is typically hidden away with a dependency injection container.

    If you have a more specific scenario, I can try to give a more specific answer.
    I see, thats good to know, after all avoiding Statics makes a program more object oriented and more unit-test friendly.

    One example I can think of starts with a Unit of work, in Martin Fowler's book he designs lots of static methods for easy manipulation of Unit Work directly from Domain Model(as models need to set themselves to be new, dirty, clean or removed). In theory you can design all your domain models to accept a Unit of Work object to avoid having to use Unit of Work, it looks fine this way. And then I want to introduce Identity Map, something that can be a part of Unit of Work or not. You may say that an identity map can be a part of Unit of Work, but in my case I prefer them separated. This makes two dependent objects that need to pass inside a domain model's constructor. The story continues, and sometimes you end up with 5+ dependent objects that make your constructor messy and object creation process a pain to handle.

    Apparently you agree that dependency injection containers will help, but I wonder how it works in action. Do you have an example of dependency injection container and how it works in action? Just wondering. Of course I am referring to common and large dependent objects such as a Database Object, HTTPRequest Object, UnitOfWork, the reason why many frameworks use statics to begin with is that instantiating such a duplicated object is costly when it comes to performance/benchmark.

  4. #4
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,156
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Apparently you agree that dependency injection containers will help, but I wonder how it works in action. Do you have an example of dependency injection container and how it works in action?
    There are varying levels of sophistication. Some dependency injection containers (DICs) allow you to configure the container through config files. Or some will try to auto-detect dependencies for you. But the very simplest DIC could be just a straightforward class such as this:

    PHP Code:
    class Container
    {
        public function 
    getMailTransport()
        {
            return new 
    Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
                
    'auth'     => 'login',
                
    'username' => 'foo',
                
    'password' => 'bar',
                
    'ssl'      => 'ssl',
                
    'port'     => 465,
            ));
        }
     
        public function 
    getMailer()
        {
            
    $mailer = new Zend_Mail();
            
    $mailer->setDefaultTransport($this->getMailTransport());
     
            return 
    $mailer;
        }

    Normally, to create a Zend_Mail object, you would first have to create a transport object, and to create a transport object, you would have to pass in several constructor arguments. But now all that dependency logic is "contained" within the container. Now creating a Zend_Mail object is as simple as:

    PHP Code:
    $mailer $container->getMailer(); 
    If you wanted to make sure that only one mailer object is ever created...

    PHP Code:
    class Container
    {
        private 
    $shared = array();

        
    // ...

        
    public function getMailer()
        {
            if (isset(
    $this->shared['mailer'])) {
                return 
    $this->shared['mailer'];
            }

            
    $mailer = new Zend_Mail();
            
    $mailer->setDefaultTransport($this->getMailTransport());

            
    $this->shared['mailer'] = $mailer;

            return 
    $mailer;
        }

    "First make it work. Then make it better."

  5. #5
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    344
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    I see, thats very interesting. Thank you so much for an example like this. I wonder though, do you think its a good idea to group certain commonly used utility classes into a package class for easier dependency injection. For instance, I have a Request class, a Response class, a Cookie class and a Session class, all of them are used for handling Front/Page Controller actions, would it be good to write a DI Container class for these four? Similarly for Database, Cache and other data-related classes that may be necessary for Domain Model layer?

  6. #6
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,156
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    I wonder though, do you think its a good idea to group certain commonly used utility classes into a package class for easier dependency injection. For instance, I have a Request class, a Response class, a Cookie class and a Session class, all of them are used for handling Front/Page Controller actions, would it be good to write a DI Container class for these four? Similarly for Database, Cache and other data-related classes that may be necessary for Domain Model layer?
    I'm not clear what you mean by "package class," but I'm inclined to say no, it's not a good idea. As much of your code as possible should be completely unaware that a container exists. For example, neither the Zend mail nor transport classes are aware that they're being composed by a container.
    "First make it work. Then make it better."

  7. #7
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    344
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    I'm not clear what you mean by "package class," but I'm inclined to say no, it's not a good idea. As much of your code as possible should be completely unaware that a container exists. For example, neither the Zend mail nor transport classes are aware that they're being composed by a container.
    I see, thanks for the clarification.

  8. #8
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    666
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Is it even possible? And how difficult can it be? Just wondering, I know that Dependency Injection can solve this problem for a smaller system, but in larger systems you have to pass 5+ dependent objects in the constructor this can be a messy work. How about Dependency Injector(Container)? Is it gonna help in this situation?
    Here is a nice 12 step plan for creating your own framework: http://fabien.potencier.org/article/...ponents-part-1

    It's written by the creator of Symfony. Doubt if you will find any static stuff in there. Dependency injection is discussed in part 12.

    Silex is also an interesting micro framework to study. It's main application object actually extends a dependency inject container called pimple.

  9. #9
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,156
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ahundiak View Post
    Here is a nice 12 step plan for creating your own framework: http://fabien.potencier.org/article/...ponents-part-1
    +1

    Also, here's an updated copy of that same series.

    https://github.com/fabpot/Create-Your-Framework
    "First make it work. Then make it better."


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
  •