Return type hinting is great!

When I use my IDE and experiment with classes that I haven’t used before, I really love that it tells me what kind
of object a method returns to me. My IDE doesn’t use Artificial Intelligence to know that, it reads the PHP docblocks.

class Importer
{
    /**
     * @return $this 
     */
    public function setBaseUrl($url)
    {
        $this->baseUrl = $url;

        return $this;
    }
}

In this small post I’ll tell you about the @return tag. Return tags tell you about what you can expect to get
returned from a function or method.

Primitive types

A return type can be a primitive type like string, bool (ar the alias boolean), true, false, null, int (or alias integer), float,
array, callable or resource. There is also the primitive type void which indicates that the method will return nothing
(in PHP this will be equal to null), but the PSR-5 draft
says @return void may be omitted. No need to write something that is optional and unmistakeable, right? So I personally
never write @return void.

Regular types

One last primitive type is object. If you’re going to return an object, better make all returned objects implement a
common interface and use that as type hint. Even if the interface is completely empty.

In the case of a mutable object you often find @return $this to be used.
This indicates that the setter, or any other method that changes the state of the object, will return the exact same
instance as on which the previous method was invoked on. After a chain of invoked methods, the returned object is still
the same object as the original one.

This is different from immutable objects:

An immutable object never modifies itself but returns a new object instead.

When you’re dealing with Immutable objects, a different kind of return type is required. @return ImmutableFoo
will indicate that this method on the object of type ImmutableFoo will return an object of type ImmutableFoo but not the same.
@return self will remove the need to retype the class name, of FQCN, in every return tag.

Late static binding

Imagine an interface ImmutableContainer with a method public function add($key, callable $resolver);. Whenever the add
method is called on an implementing container, the container is supposed to clone itself, add the binding to the new container,
and return that new instance. In that case this is what add method should be documented like:

interface ImmutableContainer
{
    /**
     * @param string $key
     * @param callable $resolver
     *
     * @return static
     */
    public function add($key, callable $resolver);
}

It says: whatever class is implementing this, it will return a new object of its own type. It’s consistent with
PHP’s Late Static Binding feature and interpreted that way by your IDE.

Mixing return types

The @param docblock tag sometimes has a compound set of types it accepts. For example @param int|DateTimeInterval $ttl.
This means the method accepts both an integer and a DateTimeInterval to define what TTL (Time To Live) value to use. As long the description
includes the unit of the TTL value when it’s an integer (eg: TTL in seconds), this is all fine.

But when it’s about a return value, I’m very strongly against using compound return types. You don’t want everyone who’s
using a given method to check the type of the returned value. When a method would either return a certain type of object or
null to denote a failed action, the method should probably throw some kind of exception instead.

Edit
It turns out there is a use case for compound return types!

In this case the method returns an array of objects (like @return DateTime[]), and more specifically a Collection object that implements the ArrayAccess and Traversable interfaces. This return tag, @return Collection|DateTime[], does leave room for the person using the method to handle the returned value in any way he/she wants. Thanks, Barry, for the suggestion!

When you really don’t have a clue what a method will return, the type hint should be @return mixed. There are only a handful of places where this makes sense. One being a get (or make) method on an IoC container. Another use case I see is when values are retrieved from a data store, like from a Cache store, where all values are unserialized before being returned.

Native return types

Of course, when we’re all running on PHP 7 we can have proper return types!

References

PSR-5 draft
PHPDocumentor explanation on keywords
PHP 7 Return types

Happy type hinting!