Distrakt
+44 (0) 121 212 9737 / team@substrakt.com
© 2018 Substrakt Registered in England. Company no. 5916054

Working with Return Types in PHP

April 25, 2018

Ensuring that your methods and functions always return a value of the same type is great step towards making your applications robust and easy to maintain.

In the Substrakt developer team, we endeavour to use the same return type for both the truthy and the falsey responses in our methods and functions.

Consistently returning the same type means that we can always trust the response of a function or method. It also means that if mistakes are made and the response is treated as truthy, even when it’s not, the application will often fail gracefully.

For example, let’s say we had a `Dictionary` class with a method that returned a list of all the words that were less than 10 characters long.

/**
 * Returns a list of words that are shorter than 10 characters.
 * @return array
 */
public function shortWords()
{
    return array_filter($this->words(), function($word) {
        return strlen(trim($word)) < 10;
    });
}

If we used the following function, `shortWords` would be prone to failure if the `words` property was not an array.

/**
 * Returns the words property.
 * @return array
 */
public function words()
{
    return $this->words;
}

However, if we take the extra steps to validate the `words` property before falling back to return a consistent falsey type value we can prevent the application from breaking when there is unexpected data in `words`.

/**
 * Returns the words property.
 * @return array
 */
public function words()
{
    if (!empty($this->words) && is_array($this->words)) {
        return $this->words;
    }

    return [];
}

What’s more, this consistency will give you and your team a level of trust in your application that allows you to write code with a little more speed and brevity.

Return Type Declarations

PHP 7.0 now supports return type declarations (RTD) which allow you to specify the return type of a method or function in its signature.

Meaning this:

/**
 * Returns the events property.
 * @return array
 */
function events()
{
    return $this->events;
}

Becomes this:

/**
 * Returns the events property.
 * @return array
 */
function events(): array
{
    return $this->events;
}

Using the latter forces the application to error if the `events` property is not an array, removing a level of uncertainty from your application whilst improving the overall code readability.

Peter Lafferty did a great job of concisely demonstrating the benefits of RTD in PHP in this feature on Medium.

Known Caveats

Working with RTD and consistent return type data can be tricky when working with objects because returning a falsey object is not currently possible in PHP — all objects are treated as truthy.

This is where implementing some variety of Null Object pattern will come in handy.

With a Null Object, you should be able to call methods even when they don’t exist.

For example, let’s look at this `masthead` method and let’s assume that `Attachment` is a class of image methods and that `mastheadID` returns 0 — we’re going to get `NullObject` returned back to us..

/**
 * Returns the page masthead image.
 * @return object Attachment|NullObject
 */
public function masthead(): object
{
    if ($id = $this->mastheadID()) {
        return new Attachment($id);
    }

    return new NullObject;
}

If `NullObject` is working as expected, then we should safely be able to call one of the `Attachment` class methods and get a falsey value in response from the `NullObject`, like this:

if ($url = $page->masthead()->url()) {
    echo "<img src='{$url}'>";
}

Alternatively, you could simply use the SPL function `get_class` on `$page->masthead()` although I find that this approach tends to be more verbose than simply calling a method, like in the above example.

Watch this space for more information on Null Objects as Stu, our technical director, will be covering his Null Object pattern in the next development blog.

Thanks for reading and if you have any questions on return type declarations, type declarations or programming principles hit me up (@itomcash) or one of the team (@substrakt) on Twitter.

Tom Cash