Named Constructors in PHP

The named constructor pattern lets you to have multiple means of instantiating an object in a semantic manner. Aside from the added readability, this pattern can also compensate for PHP’s lack of method overloading.

A Value Object Example

We’ll start with an example. This is a regular old constructor.

class DisplayColour
{
    public function __construct(int $red, int $green, int $blue)
    {
        if ($red < 0 || $red > 255) {
            throw new \DomainException("Red value must be between 0 and 255.");
        }

        // More guard statements...

        $this->red = $red;
        $this->green = $green;
        $this->blue = $blue;
    }
}

This is the constructor of a value object that represents a colour to be displayed on a screen with 24-bit colour depth. We use scalar type declarations (available in PHP 7) to ensure the parameters are integers. We have some guard statements to enforce our business rules, which are that each value must be between 0 and 255. If the guard statements are passed then the constructor just assigns the parameters to the corresponding class properties.

Let’s say that we’re using this object in a context where it may need to be created from HSL values as well as RGB values, such as a colour picker. In that case, we’ll need a more “flexible” constructor, right? Let’s modify our constructor to handle both cases.

class DisplayColour
{
    public function __construct(
        int $redOrHue,
        int $greenOrSaturation,
        int $blueOrLightness,
        bool $isRgb = true
    ) {
        if ($isRgb) {
            if ($redOrHue < 0 || $redOrHue > 255) {
                throw new \DomainException("Red value must be between 0 and 255.");
            }
        } else {
            if ($redOrHue < 0 || $redOrHue > 360) {
                throw new \DomainException("Hue value must be between 0 and 360.");
            }
        }

        // More guard statements...

        if ($isRgb) {
            $this->red = $redOrHue;
            $this->green = $greenOrSaturation;
            $this->blue = $blueOrLightness;
        } else {

            // Convert HSL values to RGB values and assign...

        }
    }
}

Now we need a flag to tell us if the given values are RGB or HSL, since each case requires the same number and type of parameters. We can set the flag to true by default, which means we won’t have to update any existing usages of the constructor. We’ll need different guard statements for each set of input values, because we have different business rules for them: A red value must be between 0 and 255 while a hue value must be between 0 and 360.

We’re already storing the values internally in our class properties as RGB so we can pass the parameters straight through in the RGB case. In the HSL case though we’ll need to convert the values to RGB before we assign them.

What if our colour picker needs to handle hex values as well?

class DisplayColour
{
    public function __construct(
        $redOrHueOrHexValue,
        int $greenOrSaturation = null,
        int $blueOrLightness = null,
        bool $isNotHsl = true
    ) {
        // Here be dragons...
    }
}

The first parameter can now also be a hex value, which is a string rather than an integer, so we’ll need to drop the type declaration. We can just add more guard statements to check the type for us though. We’ll add some defaults to the next two parameters so that our hex DisplayColours can be created without having to pass in null ourselves.

We can maintain backwards compatibility with existing usages if we change our flag to mean that the given values are no HSL rather than that they are RGB. I’ll leave the possible implementations of this constructor to your imagination.

What if we kept the previous constructor and instead created a named constructor for handling hex values?

class DisplayColour
{
    public static function fromHex(string $value)
    {
        if (strlen($value) !== 6) {
            throw new \DomainException("Hex value must be 6 characters long.");
        }

        // More guard statements...

        return new self(
            $red   = hextodec(substr($value, 0, 2)),
            $green = hextodec(substr($value, 2, 2)),
            $blue  = hextodec(substr($value, 4, 2))
        );
    }
}

A named constructor is just a static factory method on a class. This one takes in a single string parameter, ensures that it abides by our business rules for hex colour values and then converts it to RGB values before passing those to the actual constructor itself.

class DisplayColour
{
    public static function fromHsl(int $hue, int $saturation, int $lightness)
    {
        if ($hue < 0 || $hue > 360) {
            throw new \DomainException("Hue value must be between 0 and 360.");
        }

        // More guard statements...

        // Convert HSL values to RGB values...

        return new self($red, $green, $blue);
    }
}

This is a named constructor for HSL values. The method signature is much clearer than our dual purpose constructor was. We no longer have a need to include boolean flags to determine what the input values represent, so we can return our actual constructor to its original state.

While we’re at it, let’s make a named constructor for the original RGB case as well.

class DisplayColour
{
    public static function fromRgb(int $red, $int $green, int $blue)
    {
        return new self($red, $green, $blue);
    }

    private function __construct(int $red, int $green, int $blue)
    {
        if ($red < 0 || $red > 255) {
            throw new \DomainException("Red value must be between 0 and 255.");
        }

        // More guard statements...

        $this->red = $red;
        $this->green = $green;
        $this->blue = $blue;
    }
}

We just pass the parameters straight through to the actual constructor. We keep the type declarations and the guard statements in the actual constructor to continue enforcing those business rules at all times. We also make the constructor private, so client code can only access it via one of the named constructors.

Imagine as we continue developing our DisplayColour we discover that it would be easier to do calculations if the values were stored as HSL rather than RGB. We can change the implementation of our value object while keeping the same interface we have already developed.

class DisplayColour
{
    public static function fromRgb(int $red, int $green, int $blue) { ... }
    public static function fromHsl(int $hue, int $saturation, int $lightness) { ... }
    public static function fromHex(string $value) { ... }

    private function __construct(int $hue, int $saturation, int $lightness)
    {
        // Guard statements...

        $this->hue = $hue;
        $this->saturation = $saturation;
        $this->lightness = $lightness;
    }
}

In this way no client code is affected. The RGB and hex constructors would convert their values to HSL while the HSL constructor would just pass the parameters straight through.

Benefits of Named Constructors

So why should you use named constructors in your code?

Readability

Our source code will be approachable for others and our future selves. The implementations will be easy to parse without nested branches all over the place. If someone only needs to look at one way the object is constructed, they avoid reading unrelated code.

Extensibility

// Import some colour values as strings...
$bgHex = "ffe375";
$fgHex = "333";

$backgroundColour = DisplayColour::fromHex($bgHex);

// This won't work...
$foregroundColour = DisplayColour::fromHex($fgHex);

// Add a new named constructor!
$foregroundColour = DisplayColour::fromShortHex($fgHex);

Imagine we’re reading colour values from CSS. Some of the hex codes could be in shorthand notation. We could dive into our hex constructor and attempt to modify it, or we can just create a new named constructor. As a corollary, if we discover we’re no longer using a named constructor in any client code it is just as easy to remove it as to add a new one.

Expressiveness

$colour = new DisplayColour(232, 80, 66);

From the constructor you might think that the colour is red, since 232 is a high red value. But it could also be blue, as 232 is a bluish hue value. If we use a named constructor our code expresses its meaning better.

$colour = DisplayColour::fromRgb(232, 80, 66);

Naming Conventions

$date = Carbon::createFromTimestamp(1451566800);

A lot of well-known packages, such as the Carbon datetime library, use this “create from” naming convention.

$oneHundred = Emoji::fromCode(":100:");

echo $oneHundred->toCode(); // :100:

Personally I like using just “from” as a prefix. It complements any “to” methods I might also have on the object.

$plusOne = Emoji::thumbsUp()

return Emoji::null();

You can drop the prefix if the named constructor is going to consistently return the same object. I find null constructors very useful when I’m using the null object pattern.

The important part is to be consistent about the naming convention you choose. If not across your whole code base then at least within specific contexts.

Conclusion

Starting to use this pattern is very easy. Gradually introduce named constructors to any value objects you already have. Remember to give any new value objects you create named constructors.

Even if you only need one way to create an object, it still provides the benefits.


This blog post is based on a talk given at PHP Dublin in April 2016.