well used interfaces

Like masks, interfaces allows us to recognize object capabilities.

 

What are interfaces ?

Interfaces, in PHP as in all other OOP languages, specify what methods must be implemented in a class. Interfaces gives names and arguments counts, but no content : the actual code will be provided by the class.

<?php

interface movable {
  function move($distance) ;
}

class human implements movable {
  public function move($distance) {
    $this->walk($distance);
  }
}

class dog implements movable {
  public function move($distance) {
    $this->run($distance); // dogs never walk...
  }
}

class marsrover implements movable {
  public function move($distance) {
    for($i = 0; $i < $distance / self::STEP; $i++) {
      $this->checkAround($distance / self::STEP);
      $this->rollWheels($distance / self::STEP);
    }
  }
}

Interfaces may be applied to arbitrary object: in fact, they are made to escape the class hierarchy. May be we could have a common Animal class for Dog and Human with move() method, but what would we do for Oysters? And robots, such as MarsRover would not fit. Here, the interface allows to gather a number of classes outside the hierarchy. All of them move!

Technically, interfaces will ensure that the implementing functions have the requested methods. This will not be check at lint time (aka, php -l), but as soon as PHP has to define the classes. This mean that the script has to be executed to get any validation.

<?php

interface movable { 
  function move();
}
 
class car implements movable {
// some other methods
}

?>
prompt> php -l test.php
No syntax errors detected in test.php
prompt> php test.php 
PHP Fatal error: Class car contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (movable::move) in /test.php on line 5

Note that a class that doesn’t implement all the interface’s method may be defined, though it must be abstracted. This way, no object can be created without all the code for the interface method. This is convenient : one may apply the interface at a high level of abstraction, but only define the method in the concrete classes.

More than simple definitions

At that level, interfaces are a nice tool to make sure that classes provide a specific set of methods and to group arbitrary classes. If this was their only role, we could get rid of them as soon as the methods were written: they would be a mere IDE helpers. Interfaces are really useful with two other PHP tools: type hinting and instanceof.

Instanceof

Instanceof checks that an object is of a class, a sub-class or an interface. Once an object have been checked, the code may safely call some of its methods and get a consistent result.

<?php
foreach($aGroupOfObjects as $unknownObject) {
  if ($ unknownObject instanceof \movable) {
    $unknownObject->move(10);
  }
}
?>

Type hint

The big brother of instanceof, related to interfaces, is type hinting. Actually, it is a bit like embedding instanceof in the method signature. This makes it easy to validate early in the method that the argument will be valid for calling some specific methods. In case a wrong object is provided, PHP emits a Catchable fatal error.

<?php

// within a class
public function goAndReturn(movable $something) {
  $something->move(10);
  $something->move(-10);
}

?>

Note that the check imposed by the interface is lighter on the argument than checking a specific class: here, we simply need the incoming object to have the move() method. Interfaces will only check a few methods, which may be written in very different way, depending on the nature of the object. Here, the method apply to humans, dogs, marsrover or yoyo. Since we only need to call one method and work with the result, this is sufficient. This will be easier at refactoring time.

Well used interfaces

Well used interfaces are interfaces that are used for class definition and they are also used with instanceof or in type hints. Checking type of value during execution reduces dramatically the possibilities of error. It makes the intention of the code clearer. Imagine the previous method without the type hint: “function goAndReturn($something)”. This will now be checked anytime the method is called during execution.

Well used interfaces are used with type hint or instanceof. Indeed, if a defined interface is never used in a type hint or with an instanceof operator, it is also time to review it and check its real usage. It may be removed, but in fact, it would probably be easier to add it to a few method definitions and make the code self checking. Give it a try!

Finally, when an interface is only implemented once, this is not a well used interface. One may wonder why this set of methods has been singled out, and couldn’t characterize more than one class. May be this wasn’t such a common pattern and is not really needed. That too, if worth a check in the code.

More reading