In a previous post, we talked about the existing relationship between type hinting and interfaces, and the fact that type hinting can lead to overuse of interfaces.

In this post, we're are going to explain where and when interfaces can be useful (outside of the type hinting concerns) in PHP.

In statically typed languages, interfaces are first used to make different classes interchangeable without breaking type safety. But this is not the property we are concerned about because PHP is a dynamically typed language so this issue doesn't apply (well expect if you are using type hinting).

But interfaces are also an alternative to multiple inheritance because, in general, multiple inheritance creates more problems than it solves (e.g the diamond problem). Moreover, when you are looking to multiple inheritance to solve a problem, most of the time the solution is to not use multiple inheritance at all! Indeed, you should always consider composition of features before you think about inheritance. For example, a Car doesn't need to extend Engine and Wheels classes! In this case, having a Car which contains an Engine instance and 4 Wheel instances makes a far more sense.

Languages like Java or C# preferred to use the interface concept instead of multiple inheritance and this is also the way chosen by PHP.

Are interfaces are "equivalent" to multiple inheritance ?

No. They're two different concepts, although both allow attaching "things" to classes, where "things" are:

  • multiple parent classes (for multiple inheritance)
  • contracts (for interfaces)

To simplify: an interface is a kind of type (like an integer, a float or whatever) but if it's too abstract for you, just see interfaces as a way to attach "contracts" to classes.

For example if a Car class implements a Vehicle interface, it only means that:

  • Car is assured to have implemented all Vehicle's methods
  • you can use instanceof to verify that an instance implements the Vehicle "contract"

What interfaces and multiple inheritance both solves ?

When you are writing business logic, you may need be able to manage some conditional behavior based on the type of an instance.

if ($instance instanceof Countable) {
    return $instance->count();
}

In the above example, if Countable is a class name it can be problematic. Indeed if $instance is an instance of a class A which extends a class B, $instance won't be able to also extend a Countable class. However if Countable is an interface, the problem disappear.

When should I use interfaces?

I'll explain this on piece of code found in the Zend Framework 2 (apologies to the author).

/**
 * Process the select part
 *
 * @param PlatformInterface $platform
 * @param DriverInterface $driver
 * @param ParameterContainer $parameterContainer
 * @return null|array
 */
protected function processSelect(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null)
{
    ...
        $table = $this->table;
    ...
        // create quoted table name to use in columns processinga        if ($table instanceof TableIdentifier) {
            list($table, $schema) = $table->getTableAndSchema();
        }

        if ($table instanceof Select) {
            $table = '(' . $this->processSubselect($table, $platform, $driver, $parameterContainer) . ')';
        } else {
            $table = $platform->quoteIdentifier($table);
        }
    ...
}

People often use interfaces in method declarations (where they can be of little value), but miss the opportunity to use them in strategic places! In the above piece of code, all instanceof statements should have been applied on interfaces instead of a class name. Indeed, if your class already extends another parent class, you won't be able to use your class implementation with the above piece of code!

In conclusion, interfaces in dynamic languages should not be thrown around indiscriminately. The fact that "type hinting" seems to be a practice adopted by many frameworks and libraries tends to lead to interface abuse, and creates problems which never needed to exist!

So, if you want to make you life easier, just avoid type hinting and use interfaces only when they really add value!

PS: For those who are using some dependency injection system based on a DI container which introspects the code using the PHP reflection layer to extract the "type hint" of methods parameters to automatically inject instances of the correct type, I think simpler approaches need to be considered here.