Interfaces are definitions of the public APIs classes must implement to satisfy the interface. They work as "contracts", specifying what a set of subclasses does, but not how they do it.
Interface definition is much alike class definition, changing the keyword class
to interface
:
interface Foo {
}
Interfaces can contain methods and/or constants, but no attributes. Interface constants have the same restrictions as class constants. Interface methods are implicitly abstract:
interface Foo {
const BAR = 'BAR';
public function doSomething($param1, $param2);
}
Note: interfaces must not declare constructors or destructors, since these are implementation details on the class level.
Any class that needs to implement an interface must do so using the implements
keyword. To do so, the class needs to provide a implementation for every method declared in the interface, respecting the same signature.
A single class can implement more than one interface at a time.
interface Foo {
public function doSomething($param1, $param2);
}
interface Bar {
public function doAnotherThing($param1);
}
class Baz implements Foo, Bar {
public function doSomething($param1, $param2) {
// ...
}
public function doAnotherThing($param1) {
// ...
}
}
When abstract classes implement interfaces, they do not need to implement all methods. Any method not implemented in the base class must then be implemented by the concrete class that extends it:
abstract class AbstractBaz implements Foo, Bar {
// Partial implementation of the required interface...
public function doSomething($param1, $param2) {
// ...
}
}
class Baz extends AbstractBaz {
public function doAnotherThing($param1) {
// ...
}
}
Notice that interface realization is an inherited characteristic. When extending a class that implements an interface, you do not need to redeclare it in the concrete class, because it is implicit.
Note: Prior to PHP 5.3.9, a class could not implement two interfaces that specified a method with the same name, since it would cause ambiguity. More recent versions of PHP allow this as long as the duplicate methods have the same signature[1].
Like classes, it is possible to establish an inheritance relationship between interfaces, using the same keyword extends
. The main difference is that multiple inheritance is allowed for interfaces:
interface Foo {
}
interface Bar {
}
interface Baz extends Foo, Bar {
}
In the example bellow we have a simple example interface for a vehicle. Vehicles can go forwards and backwards.
interface VehicleInterface {
public function forward();
public function reverse();
...
}
class Bike implements VehicleInterface {
public function forward() {
$this->pedal();
}
public function reverse() {
$this->backwardSteps();
}
protected function pedal() {
...
}
protected function backwardSteps() {
...
}
...
}
class Car implements VehicleInterface {
protected $gear = 'N';
public function forward() {
$this->setGear(1);
$this->pushPedal();
}
public function reverse() {
$this->setGear('R');
$this->pushPedal();
}
protected function setGear($gear) {
$this->gear = $gear;
}
protected function pushPedal() {
...
}
...
}
Then we create two classes that implement the interface: Bike and Car. Bike and Car internally are very different, but both are vehicles, and must implement the same public methods that VehicleInterface provides.
Typehinting allows methods and functions to request Interfaces. Let's assume that we have a parking garage class, which contains vehicles of all kinds.
class ParkingGarage {
protected $vehicles = [];
public function addVehicle(VehicleInterface $vehicle) {
$this->vehicles[] = $vehicle;
}
}
Because addVehicle
requires a $vehicle
of type VehicleInterface
—not a concrete implementation—we can input both Bikes and Cars, which the ParkingGarage can manipulate and use.