Introduction
In Object Oriented Programming, interfaces specify which methods a class must implement, without defining how these methods are implemented.
You can see an interface as a combination of a blueprint and a contract:
- As a blueprint, the interface specifies the name and signature of the methods the class must implement.
- Any class that implements an interface makes a contractual agreement to really implement all the methods that are declared by the interface. Not doing so results in a fatal error.
Let's look at an example.
Basic example
The Book and Furniture classes have no relationship to each other, but they do share functionality, or capabilities: they can both be printed.
The Printable interface specifies that any class that implements Printable must provide a print() method.
In other words, you can rely on the fact all Book and Furniture objects will provide a print() method.
Interfaces vs abstract classes
You may have noticed that interfaces are similar to abstract classes:
- You can't instantiate abstract classes or interfaces.
- Abstract classes and interfaces both provide a kind of blueprint for other classes.
There is, of course, a difference:
Abstract classes are used when:
- You have a clear inheritance chain (such as
Vehicle->TwoWheeler->Bicycle->MountainBike), and: - The top-level class itself (
Vehicle) will never need to be instantiated, and: - You want to ensure all classes down the inheritance chain are guaranteed to implement certain methods.
Interfaces are used when:
- You want to guarantee that certain classes implement certain methods, without those classes necessarily having anything to do with each other.
Interfaces and polymorphism
Through polymorphism and inheritance, a method that accepts an Animal parameter will also accept a Dog or Cat parameter because those are both subtypes of the expected type Animal.
In human language you would express this as "I require the object to BE of the type Animal, or any subtype of Animal".
Instead of requiring an object of a specific type, you can also require any object as long as it implements a specific interface. In other words, you don't care about which type of object your method receives, as long as it provides an expected set of methods.
In human language you would express this as "I require the object to HAVE a certain set of methods".
Example
The createPrint() method of the Printer class accepts a parameter of any type as long as it implements the Printable interface.
This way we're no longer stuck with a strict parent/child class relationship and still define classes that (partially) behave the same way, even if their actual implementation of the shared behaviour is different:
Book and Furniture are guaranteed to provide the print() method because they both declare that they implement Printable, which specifies the presence of a print() function.
The actual implementation of the print() function can - and likely will - be different in the Human and Book classes, but you can rely on print() to be present in both classes.
Implementing multiple interfaces
While it is not possible to inherit from multiple classes in PHP, you can specify that a class implements multiple interfaces.
After all, it makes sense that unrelated, different objects could all be printable, translatable, exportable, or publishable.
Example
The above example declares three interfaces:
TranslatablePublishableDeletable).
The Book class declares that it implements these three interfaces, and you can verify that it does indeed do so: all of the methods described in the individual interfaces are present in the Book class.
The Book class also specifies a few additional properties (title, author, publisher) and a saveToDatabase() method.
The Translator class provides the translate() method, which expects to receive an object of any type, but it must implement the Translatable interface.
We then create a new Book object, set its properties, translate it, unpublish it, and delete it.
The translate() method of the Translator class:
- accepts any object that implements
Translatable, and then calls that object'stranslate()method - is certain that the object it receives implements a
translate()method thanks to its type hintTranslatable $item
Combining inheritance and interfaces
Using interfaces does not prevent you from also using inheritance:
class ImageFile extends File implements Resizable, Croppable {
// Implementation goes here.
}When fully implemented, this ImageFile class will inherit everything from the File class, and will also contain all the methods described by the Resizable and Croppable interfaces.
Summary
- Interfaces specify a set of methods that a class MUST implement.
- If a class declares that it implements a certain interface, it MUST implement all the methods specified in the interface.
- By type hinting a specific interface instead of a specific class, you accept any object as long as it implements a specific interface: you don't care about which type of object your method receives, as long as it provides an expected set of methods.
- Interfaces are more flexible than (abstract) classes:
- Classes can only inherit from one other class.
- Classes can implement more than one interface.