One of my favorite PHP interview questions, is: what is Type Hinting and why it’s important? Putting definition in one sentence, Type Hinting is a way to define type of parameter in function signature and it’s a sine qua non to leverage polymorphism. Because of dynamic typing in PHP, parameters don’t need to have type used. Also, by type here, I mean complex types (class, abstract class, interface, array, closure), not primitives like integer or double.

So given the fact, that Type Hinting is optional and we don’t need to specify types of parameters passed to the method – why bother? Answer is easy: well prepared method signatures defines your model and are part of the „contract” that your code reveals to its consumers. It also prevents many silly errors and keeps codebase clean and coherent.

Now, if we all agree that Type Hinting is the way to go, what should we put in method signatures? We have few options: concrete class, base class or an interface. It all depends on situation. The most flexible way is the interface, because it’s small definition of object behavior and one class can implement multiple interfaces. Moreover, interfaces can be very easily mocked (by both mock tools, like Mockery or by mocks written by hand). All those adds up into great flexibility

Other option is to set class as type hint. You’re limited to this class instances and their descendants. Having multi-tier hierarchy graph, it’s often good idea to use a class in hierarchy near the root or even abstract class, which gives us possibility to apply method to whole graph of inheritance.

The least flexible way is to set a concrete class (near to final or not ever extended in current sytem). In such case you limit method only to serve for such objects, which is understandable, when method does a specific job.

Three options were presented above (interface, base class and concrete class). There’s one more, very important thing, that need to be kept in mind. Although PHP allows you to call methods outside the type that is defined for the method, you should never do that! It can lead to some bizarre errors and breaks Liskov Substitution Principle. Simply said: if you use a type in method’s signature, then it should rely only on this type, not it’s descendants (even we know about their existence), so you can substitute give type with new subclass without altering method body.

Have a look at possible violation of Liskov Substitution Principle:

class UserRepository extends \Doctrine\ORM\EntityRepository
{
    public function findActiveUsers()
    {
        // do some query to retrieve the result
        return $activeUserCollection;
    }
}

// .. 

public function notifyActiveUsers(EntityRepository $repo)
{
    if ($repo instanceof UserRepository) {
         $usersCollection = $repo->findActiveUsers();
    } elseif ($repo instanceof ManagersRepository) {
         // .. do someting else
     }
    // do something with $usersCollection
}

As we can see, type hinted method notifyActiveUsers internally relies on specific extension of EntityRepository. This breaks LSP and leads to unreadable model. Even worse situation can be following:

public function notifyActiveUsers(EntityRepository $repo)
{
    $usersCollection = $repo->findActiveUsers(); 
    // do something with $usersCollection
}

In the stage of implementation, we knew, that only EntityRepository was passed to this method. But in some random point of time, someone can pass other implementation of EntityRepository, and we have a problem. In Java, compiler wouldn’t allow you to compile such code, but in PHP it’s allowed on interpretation stage, however it will fail during runtime.

To sum things up: Type Hinting is an essential concept in OOP and should be used whenever you pass an object as a method parameter. The most flexible way is to use interfaces, but base classes often are also sufficient. One should never check or rely on subclassing of the object passed to method, because type declared in method signature, should be the final type we operate in scope of method. Applying to those straightforward rules allows us to create robust and polymorphic OOP design.