Interfaces are a universal concept across several OOP style languages. PHP definitely has them too:

  interface Animal {
    
    /**
     * Every animal has to eat, right?
     */
    public function eat();
  }

2 things to know about interfaces:

  1. They are not able to live on their own. They’re kind of like the vines of OOP, they require a instantiable thing to exist.
  2. You can’t actually define functionality inside of the methods. They just enforce the public facing contract of a class.

So if we tried to instaniate an Interface in PHP we’re setup to have a bad time:

  $impossible = new Animal;

  => Exception: Unable to instantiate an Interface

In order for us to use an Interface, we need to create a regular class that inherits the Interface:

  class Cat implements Animal {
    public function eat($food) {
      echo "nom nom $food";
    }
  }

  $cat = new Cat;
  // now we get all of the goodies that Animal provides for free in this Cat:
  $cat->eat();
  => 'nom nom'

What happens when we attempt to assign an Interface to a class that doesn’t implement the same signature?

class Cactus implements Animal {
  public function drink($water) {
    echo "gulp gulp $water";
  }
}

$plant = new Plant();

=> Exception: Expected Plant to implement eat but it is missing

Why did this break?

By implementing the Animal interface on a Cactus which doesn’t have a eat method, we broke the contract that the Animal interface guarantees.

Animal is a great example of an interfact because there is no prototypical “Animal” instance. The term Animal by itself doesn’t specify a specific red panda, lion, or crawdad. But immediately you know that this instance is not a plant.

We’ll get into the power of Interfaces combined with Type Hinting and Ruby’s equivalent in later chapters.

Making an Abstract Class in Ruby

I’m not just going to give you an example right off the bat. Cmon what’s the fun in that.

Let’s just take this to a higher level. Why does the Interface feature exist in PHP? Well, it’s a method of guaranteeing that a particular class implements some kind of signature.

When you have Cat or Armadillo inherit from Animal, you have the peace of mind knowing that any instance implementing Animal is going to have a public eat() method.

So, I have to apologize. I am so so so sorry. I lied to you again. But the truth is there is no such thing as an interface in Ruby.

This came as a shock to me when I first started learning the language. I couldn’t believe that had OOP paradigms so embedded in it’s core but it didn’t have such Interfaces!

After a few months I’ve started to realize why.

Think about the goal of an Interface and how close we can get with just the basic building blocks OOP has to offer.

Behold the official and enterprise Interface implementation in Ruby:


class Animal
  def eat
    raise 'Don\'t forget to implement the eat method' 
  end
end

I’m not kidding. Look what happens when we attempt to call eat on a Cactus:


class Cactus < Animal
  def drink(water)
    puts "gulp gulp #{water}"
  end
end

cactus = Cactus.new
cactus.eat

=> StandardError: 'Don\'t forget to implement the eat method'

So unlike PHP, the class won’t immediately break because eat is missing. That’s absolutely true. In PHP and other strongly typed languages, the compiler catches these lapses in judgement.

Because Ruby is such a dynamic language, we place our trust in tests. But after that initial shock of missing the “formal safety” of concepts like Interfaces give you - you don’t miss them.

Ruby reduces the number of built in OOP concepts. However it doesn’t limit you from implementing them. Think about it, which do you trust more? Your contractually bound classes or your automated tests?

PHP gives us both, the ability to create contracts with the peace of mind of knowing exactly that a public interface exists - also the power of automated tests with PHPUnit and Codeception.

Yes it’s true in Ruby you’ll need to test more to make up for lack of contracts and type hinting. However, it’s because of Ruby’s dynamic nature and flexiblity to bend the rules testing your actually code becomes a blissful experience. Whereas in it’s PHP cousin, if you don’t build with tests in mind, at a certain point your code becomes virtually untestable.