Static Factory Methods aka Named Constructors

We have various ways to create an object instance. You can use the “new” keyword, employ a Factory or Builder Method, or inject it using an IoC Container.

At times, there might be a situation where an object can be initialized in multiple ways, primarily based on the parameters provided. Even though it’s still the same kind of object, there’s no necessity for inheritance or splitting into numerous parent-child classes. In such cases, using multiple constructors might be the solution.

Many programming languages, such as Java and C++, support method overloading. However, PHP doesn’t have this feature. So, how can we handle such a scenario in PHP?

Named Constructors

While the term “Named Constructors” is widely recognized in the PHP community, its original name is “Static Factory Pattern” It provides a neat solution to this problem. The fundamental idea here is to make the __construct method private and create separate methods responsible for object instantiation. This approach bears some resemblance to the Singleton pattern but with two primary differences: we utilize multiple initialization methods, and within these methods, we consistently generate a new object instance (by invoking the private constructor).

Details

A crucial aspect of this approach is that the multiple initialization methods should be descriptively named. These names should clearly communicate the context or intention of our object initialization.

To illustrate, consider the following class, which can be enhanced to avoid excessive IF statements (among other issues. Can you spot at least two?):

class SystemPowerCompany 
{
    private $kwh;

    public function __construct(float $khw = null, int $amount = null, int $persons = null)
    {
        if ($amount !== null) {
            $this->kwh = $amount / config('gross_1kwh');
        } elseif ($persons !== null) {
            $this->kwh = $persons * config('person_1kwh'); 
        } else {
            $this->kwh = $khw;
        }
    }

    public function getKwp(): float
    {
        return $this->kwh;
    }
}

Solution

Below is an example class that offers a more elegant solution. Its intentions should be clear without further elaboration.

class SystemPowerCompany implements ISystemPower
{
    private $kwh;

    protected function __construct(float $khw)
    {
        $this->kwh = $khw;
    }

    public function getKwp(): float
    {
        return $this->kwh;
    }

    public static function fromKwh(float $kwh): ISystemPower
    {
        return new self($kwh);
    }

    public static function fromInvoice(int $amount): ISystemPower
    {
        $kwh = $amount / config('gross_1kwh');
        return new self($kwh);
    }

    public static function fromPersons(int $persons): ISystemPower
    {
        $kwh = $persons * config('person_1kwh');
        return new self($kwh);
    }
}

With this design, we have compact, encapsulated blocks, ensuring that at least one of them is invoked to instantiate the object.

Wondering about that two issues from initial code?

This code that is presented before refactor contains at least two main issues – that are: 
1. From outside, when you want to create the object, the params intention is not quite clear. It doesn’t say that a) you have to set at least one param b) you shouldn’t set multiple params 

2. There is a risk, that no params will be set – it’s not covered with the if-else statements, and you can’t predict the results of it

A special thanks to Przemek T. for providing this code example!