8

I'm in the process of learning depenency injection and inversion of control, and I think I'm starting to understand how this works:

  • Objects should not concern themselves with the creation of their own dependencies
  • Dependencies should be passed to the object (via the constructor or setter methods)
  • A DI container can do the work of creating objects with all of their required dependencies

If this is all correct, can I no longer use what I call "reference methods" in my objects?

Here is what I mean by reference methods. Say I have two models for families and family members. I find it very helpful to create methods that reference objects that relate to that model. In the example below, when calling $family->members(), I can quickly gain access to all the family members. But, this would mean that my family object is instantiating family_member classes...and doesn't this break the rules of IoC?

What if the family_member class had a dependency that was outside of the scope of the family class? Input here would be much appriciated!

<?php

    class family
    {
        public $id;

        public function members()
        {
            // Return an array of family_member objects
        }
    }

    class family_member
    {
        public $family_id;
        public $first_name;
        public $last_name;
        public $age;
    }
Jonathan
  • 18,229
  • 10
  • 57
  • 56
  • I m not sure if the php is very convenient for dependency injection. There are dependency injection libraries like Guice, Spring, Ninject, Structuted map etc. if you look at them you will have a better understanding. – DarthVader Oct 24 '11 at 20:25
  • @DarthVader: Thanks for the comment. I think people are using DI in PHP. I have looked at a bunch of PHP DI containers (Symfony, Bucket, Twittee, Pimple). I think PHP 5.3 has made it easier. As for my question, I'm not sure that it matters if it is PHP or not...how would you handle this in any language? – Jonathan Oct 24 '11 at 20:32

3 Answers3

5

Disclaimer: I'm just learning DI myself. Take the answer with a grain of salt.

Dependency injection is only about injecting dependencies. If your object oriented design results in Family object having the responsibility to create instances of Member, then by all means, have the Family object create the Member, because in that case, Member is no longer considered a dependency of Family, but a responsibility. Therefore:

class Family
{
    /**
     * Constructor.
     * 
     * Since you have decided in your OO design phase that this
     * object should have the responsibility of creating members,
     * Member is no longer a dependency. MySQLi is, since you need
     * it to get the information to create the member. Inject it.
     *
     */
    public function __construct($id, MySQLi $mysqli)
    {
        $this->id = $id;
        $this->mysqli = $mysqli;
    }

    /**
     * Query the database for members data, instantiates them and
     * return them.
     *
     */
    public function getMembers()
    {
        // Do work using MySQLi
    }
}

But if you think about it, does Family really should have the responsibility of creating Member? A better design is to have another object, such as FamilyMapper create Family along with its members. Like this:

class FamilyMapper
{
    /**
     * Constructor.
     * 
     * A better OO design, imho is using the DataMapper pattern.
     * The mapper's responsibility is instantiating Family,
     * which means it's going to have to connect to the database,
     * which makes MySQLi its dependency. So we inject it.
     *
     */
    public function __construct(MySQLi $mysqli)
    {
        $this->mysqli = $mysqli;
    }

    public function findByID($familyID)
    {
        // Query database for family and members data
        // Instantiate and return them
    }

}

class Family
{
    /**
     * Constructor.
     * 
     * Family is an object representing a Family and its members,
     * along with methods that *operate* on the data, so Member
     * in this OO design is a dependency. Inject it.
     *
     */
    public function __construct($id, MemberCollection $members)
    {
        $this->id;
        $this->members;
    }

    public function getMembers()
    {
        return $this->members;
    }
}

Using this pattern, your domain objects, along with their methods (which may contain business logic) will be decoupled from your data access code. That's the good thing about dependency injection - it forces you to rethink your OO design, so that you end up with cleaner code.

Many people think that using dependency injection means not using factories and such. This is wrong! Dependency injection is only about injecting dependencies. You can use dependency injection with factory objects too, by injecting dependencies to the factory instead of having the factory instantiating its own dependency.

Useful links:

  1. http://martinfowler.com/articles/injection.html
  2. Does anyone have a good analogy for dependency injection?
  3. How to explain dependency injection to a 5-year-old?

Additions

Again, take the stuff below here with a grain of salt.

Please also note that there is a difference between dependency injection and dependency injection container. The first one is a simple concept of injecting dependencies instead of having objects creating it themselves (which results in very high coupling). We see this from the example above.

The latter is a term for frameworks/libraries that deal with dependency injection so you don't have to do manual injection. The container's responsibility is wiring dependencies so you don't have to do the dirty work. The idea is you define a dependency injection configuration, which tells the container what dependencies Foo object has, and how to inject them. The container reads the documentation and performs the injection for you. This is what DIC libraries like Pimple, SimpleDIC do.

You can compare dependency injection containers with factories, since both are a creational objects, whose sole responsibility is to create objects. While factories are often specialized (i.e. FamilyMemberFactory creating instances of MemberInterface), dependency injection container is more general. Some people say using dependency injection container relieves you of the need for factories, but you should remember that it means you have to create and maintain dependency injection configuration files, which could be thousands of XML/PHP lines.

I hope this helps.

Community
  • 1
  • 1
rickchristie
  • 1,640
  • 1
  • 17
  • 29
  • Thanks a lot @rickchristie - that was very helpful! I was doing some reading on data mappers last night, and I can really see their value. I think part of my challenge to date has been with ActiveRecord style ORM class that directly extends my domain models. While they work great in small projects, they make it more difficult to separate concerns in larger projects. A question for you - in your opinion, where should a domain models responsibilities start and stop? – Jonathan Oct 25 '11 at 12:56
  • @Jonathan Paraphrasing Martin Fowler, "Domain model is the logic that is the real part of the system". Yes, that means **all** the core stuff that your application is supposed to do belongs to domain model. Yes, it's big - it's supposed to be the biggest part of your application and the most important one. The presentation layer and the data source layer is the other big parts. – rickchristie Oct 25 '11 at 14:24
  • @Jonathan - If you haven't already, please read Martin Fowler's Patterns of Enterprise Application Architecture. It's a classic. It will tell you the most important thing about layering at the first chapter, and you will understand why we need to separate applications in layers in the first place. – rickchristie Oct 25 '11 at 14:26
  • @Jonathan - I've added some details in the answer that might also help you. – rickchristie Oct 25 '11 at 14:45
  • Thanks for your comments. I will have to pick up that book! My question was slightly wrong though - what I meant to ask is where does the role of entities start and stop? As in the (value?) objects farthest down the line, which in my case are typically representations of database tables. In my example above, these would be the `families ` and `family_members`. Should these be performing operations (like DB access), or should these just be basic containers...with simple functions for data access, such as `get_full_name()` returns `$first_name` and `$last_name`? – Jonathan Oct 25 '11 at 14:47
  • Okay cool, thanks for that update. I think I'm pretty clear now on what the difference between what factories and DI containers is...factories seem to be more built into an application, as classes or methods, where as a DI container is almost external from your domain models, piecing things together for you. – Jonathan Oct 25 '11 at 14:55
  • @Jonathan you might also be interested in Eric Evans book Domain Driven Design which has more information about Entities and ValueObjects and their responsibilities. I guess explaining their roles in the comment section is out of scope. – Gordon Oct 25 '11 at 14:56
  • @Gordon Haha, yeah, I was just going to ask an interface related question as well but figured I should keep this question focused on DI. I just find there are so many different designs/opinions/theories to OOP that it's difficult to know exactly how to piece it all together. I will look into that book as well, thanks a bunch! – Jonathan Oct 25 '11 at 14:59
  • 2
    @Jonathan - Unfortunately I'm not knowlegeable enough to answer that question. But if I have to take a stab at it, if you use the Data Mapper pattern, domain objects are not supposed to be aware of the persistence (often database) layer. The idea is to have the domain object's responsibility focused on business logic, and have another set of classes (data mappers) handle the persistence (select, update, delete methods). This makes your domain objects decoupled from the data source layer, changes at database only ripple to data mappers. Also, what Gordon said. – rickchristie Oct 25 '11 at 15:01
  • @Jonathan yeah, OOP looks quite simple on the surface but there is a lot to understand about it. If you are looking for good books then I can recommend the Addison-Wesley Signature Series. None of the deal with PHP though. – Gordon Oct 25 '11 at 15:04
  • Thanks again @rickchristie for taking the time to explain this to me. I think since you're in the process of learning this as well, that you were able to simplify it into terms that I could understand. Thanks to the others for their responses as well, it's very much appreciated! – Jonathan Oct 25 '11 at 15:11
1

While you can go with dependency injection only and all the way, trying to find a balance in your design while keeping it maintainable is a more sane approach, in my opinion.

As such, a combination of dependency injection and factories will make your life much easier.

class family {
    protected $_members;

    public function __construct($members = array()) {
        $this->_members = array_filter($members, function($obj){
            return ($obj instanceof family_member);
        });
    }

    public function addMember() {
        $this->_members[] = $member = $this->_createMember();
        return $member;
    }

    protected function _createMember() {
        return new family_member;
    }
}

The factory pattern is somewhat compatible with inversion of control and dependency injection. While dependency injection frees your object from creating its dependencies, the factory pattern lets it create a base implementation of a dependency. And in the end, it still allows you to override object dependencies when required:

class familyExtended extends family {
    protected function _createMember() {
        return new familyExtended_member;
    }
}

This is especially useful when testing:

class familyTestable extends family {
    protected function _createMember() {
        return new family_memberFake;
    }
}

Dependency injection is great, but it cannot solve all your design problems. Of course, they are not interchangeable. The factory pattern do things DI can't and vice-versa.

netcoder
  • 66,435
  • 19
  • 125
  • 142
  • Thanks @netcoder. That is sort of how I feel right now...DI makes good sense in theory, but I'm having a hard time understanding/seeing what that actually looks like in my apps. I'm starting to think that my biggest issue with DI is managing the scope. For example, I may need to create a new object that requires: 1. a **new** dependency instance and 2. an **existing** dependency instance. Without having some sort of global access to that DI container - this isn't possible. But at that point, all my objects depend on the DI container...the very thing I was trying to avoid! Ahh!!! – Jonathan Oct 24 '11 at 22:28
0

The problem is that the whole idea behind DI is that Family should not know how to create a specific FamilyMember, for instance, you should have an IFamilyMember and implementations for it may vary on each module / layer of your application.

Should be something like this:

public function GetMembers()
{
    $members = array();

    foreach ( $member in $this->internalMemberList ){
       // get the current implementation of IFamilyMember
       $memberImpl = $diContainer->Resolve("IFamilyMember");

       $memberImpl->Name = $member->Name;
       //.... Not the best example....
    }

    return $members;
}

Basically, everything sums up to the idea that components should be ignorants of their dependencies, and in your case, Family depends on FamilyMember, so any FamilyMember implementation needs to be abstracted from the Family itself.

For the specific case of PHP, consider checking out Symfony, which does heavy use of the DI pattern or you can consider using the Symfony Dependency Injection framework, which is a part of Symfony, but can be used as a separate component. Also Fabien Potencier has written a nice article on the matter.

Hope I can help!

BenMorel
  • 34,448
  • 50
  • 182
  • 322
David Conde
  • 4,631
  • 2
  • 35
  • 48
  • Thanks a lot for your input! That makes sense...`family` should not know how to create a `family_member`. My concern is this: almost entirely my apps depend on a database. Both of these classes have respective DB tables. So, in order to make this work my `family` class has to lookup these records for the database, and then create the `family_member` based on an interface. This seems like very tight coupling to me. Am I going about this all wrong? Are quick references like this just not worth the dependencies? How else would I go about it? – Jonathan Oct 24 '11 at 22:03
  • And one more follow up question, if I may. The `$diContainer` in your example...is this a globally accessible variable...or do I set it up as a singleton, or do I need to pass this as a dependency to each and every object that I make? Looking at some open source DI containers I couldn't really figure out the scope issue. Okay, so the container is creating all my objects for me...cool...but how do I access it from inside one of my objects? Or, once again, is this the wrong approach all together, and I shouldn't be accessing it from inside an object because I shouldn't be creating objects there? – Jonathan Oct 24 '11 at 22:09