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:
- http://martinfowler.com/articles/injection.html
- Does anyone have a good analogy for dependency injection?
- 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.