When you browse for the phrase "constructors must not do work", then in various blog posts you will find the advice to not let the constructor do work. Despite this, I am having some trouble understanding why this is the case. Additionally, this popular post suggests to take such advice with a grain of salt.
I have an example of two implementations of the same situation. In the situation, a AFactory
has a method createA
, using a B
. A
needs a query result, that B
produces. There are two ways to implement this:
Example 1:
class AFactory {
public function createA(B $b): A {
return new A($b->getQueryResult());
}
}
class A {
private $query_result;
public function __construct(array $query_result) {
$this->query_result = $query_result;
}
public function doFooWithQueryResult() {
// Do something with query result
}
public function doBarWithQueryResult() {
// Do something with query result
}
}
In the first example, the factory fetches the query result and passes it to A
's constructor. A
then merely assigns the query result to the corresponding class property. However, there is one problem here: A
does not verify if the query result is a valid data structure, i.e. an actual query result suited for A
. It does not know where it came from. The responsibility for this validation has now leaked to the AFactory
, and A
has become very tightly coupled to AFactory
. The other implementation resolves this issue, but then the constructor performs work. And apparently that is bad.
Example 2:
class AFactory {
public function createA(B $b): A {
return new A($b);
}
}
class A {
private $query_result;
public function __construct(B $b) {
$this->query_result = $b->getQueryResult();
}
public function doFooWithQueryResult() {
// Do something with query result
}
public function doBarWithQueryResult() {
// Do something with query result
}
}