php - Never instantiate objects in the constructor?
423
Is it bad instantiating objects in the constructor like this below?
class Foo
{
public function fooMethod() {
return 'foo method';
}
}
class Too
{
public function tooMethod() {
return 'too method';
}
}
class Boo
{
public $foo;
public $too;
public function __construct()
{
$this->foo = new Foo();
$this->too = new Too();
}
}
If so, how bad can it be? How should it be done properly?
Answer
Solution:
Manually instantiating classes inside another class creates implicit dependencies, which are quite hard to maintain - you will have a hard time detecting what needs to be changed if you ever need to change those
Foo
andToo
classes.So, a better way of managing dependencies is:
This way, your object dependency is explicit. Another advantage of doing this, is that some PHP frameworks, (Laravel, Zend, Symfony), allow for an automatic dependency resolution. It means, that you don't instantiate your object manually, only via some sort of factory - like this (Laravel):
And an
App
factory automatically detects yourFoo
class dependencies with some reflection magic and injects them appropriately. Other frameworks have similar capabilities, too.Also, there are some general principles in OOP, called
SOLID
which help to develop better OOP design. One of them -D
, stands forDependency Inversion
. What it means, is that you should avoidhard
dependencies, like in your code. Instead, bothFoo
andBar
classes should depend on aninterface
, like this:Now, if you ever need to change that
Bar
class with something else, all hell won't break loose, if your replacement also implements thatBarInterface
.Answer
Solution:
It's not inherently bad.
The downside is that it decreases the "testability" of your class, simply because
Boo
is now dependent on the existenceFoo
andToo
.Answer
Solution:
This depends on the size of your project.
On large projects, or long term projects, it should be changed slightly.
Ideally, you would refactor it implement Dependency Injection pattern, and maybe use a Factory to instantiate it.
Some sample code:
Answer
Solution:
It depends of your requirement and the classes. Let's says that every call to the constructor of Foo/Too you will execute a huge query to the database to get data, in that scenario I would opt to use lazy instantiation.
Of course, it's a good practice to initialize your properties on the constructor, but on real life performance could your enemy.
Example:
if you use this class only to execute
aMethodThatDoesntUsesFoo()
, it will never call the constructors of Foo/Too.if you will only execute
aMethodThatUsesFoo()
, it will only instantiateFoo
You can do this by static methods as well.