Interfaces vs Abstract Classes in PHP
Tags: php, laravel, webdev, programming
Published: 2021-07-29 14:47:38

## Introduction

I recently published a blog post that talked about [how to write better PHP code using interfaces](https://ashallendesign.co.uk/blog/using-interfaces-to-write-better-php-code). It covered the basics on what an interface was, what they could do and how you could use them to make your PHP code more extendable and maintainable.

One of the main comments that I got on the post was from developers who wanted to know "when would I use an interface instead of an abstract class?". So I thought I'd write this post to explain the differences between abstract classes and interfaces in PHP and give a brief overview of when you should use either of them.

## What Are Interfaces?

In basic terms, an interface should describe how a class implementing them will be built, they're like a blueprint describing the public methods and constants they should include.

Interfaces **can** be:

- Used to define public method signatures for a class.
- Used to define constants for a class.

Interfaces **cannot** be:

- Instantiated on their own.
- Used to define private or protected methods for a class.
- Used to define properties for a class.

Interfaces are used to define the public methods that a class should include. It's important to remember that an interface is always meant to be implemented by a class, so this is where you define just the signature of a method, for example:

```php
interface HomeInterface
{
    const MATERIAL = 'Brick';

    public function openDoor(): void;

    public function getRooms(): array;

    public function hasGarden(): bool;
}
```

and not something like this:

```php
interface HomeInterface
{
    public string $material = 'Brick';

    public function openDoor(): void
    {
        // Open the door here...
    }
    
    public function getRooms(): array
    {
        // Get the room data here...
    }
 
    public function hasGarden(): bool
    {
        // Determine if the home has a garden...
    }
}
```

According to <a href="https://www.php.net/manual/en/language.oop5.interfaces.php" target="_blank" rel="noopener noreferrer">php.net</a>, interfaces serve two main purposes:

1. To allow developers to create objects of different classes that may be used interchangeably because they implement the same interface or interfaces. A common example is multiple database access services, multiple payment gateways, or different caching strategies. Different implementations may be swapped out without requiring any changes to the code that uses them.
1. To allow a function or method to accept and operate on a parameter that conforms to an interface, while not caring what else the object may do or how it is implemented. These interfaces are often named like Iterable, Cacheable, Renderable, or so on to describe the significance of the behavior.

Using our interface above and sticking with the house analogy, we could create different classes that implement `HomeInterface`, such as `House`, `Flat` or `Caravan`. By using the interface we can be sure that our class contains the 3 necessary methods and all use the correct method signature. For example, we could have a `House` class that looks like this:

```php
class House implements HomeInterface
{
    public function openDoor(): void
    {
        // Open the door here...
    }
    
    public function getRooms(): array
    {
        // Get the room data here...
    }
 
    public function hasGarden(): bool
    {
        // Determine if the home has a garden...
    }
}
```

## What Are Abstract Classes?

Abstract classes are very similar to interfaces; they're not designed to be instantiated on their own and provide a base line implementation for you to extend from.

Taking our example above of homes, if an interface is your blueprint then an abstract class is your show room model. It works, and it's a great example of a home but you still need to furnish and decorate it to make it your own.

Abstract classes **can** be:

- Used to define method signatures for a class using "abstract" methods (similar to interfaces).
- Used to define methods.
- Used to define constants for a class.- Used to define properties for a class.
- Extended by a child class.

Abstract classes **cannot** be:
-Instantiated on their own.

To get an idea of what this means, let's look at an example abstract class:

```php
abstract class House
{
    const MATERIAL = 'Brick';
  
    abstract public function openDoor(): void;
    
    public function getRooms(): array
    {
        return [
            'Bedroom',
            'Bathroom',
            'Living Room',
            'Kitchen',
        ];  
    }
 
    public function hasGarden(): bool
    {
        return true;
    }
}
```

Our `House` class is abstract which means that we can't instantiate one of these directly. To be able to use it, we'd need to inherit from it. For example, let's create a `MyHouse` class that extends our `House` abstract class:

```php
class MyHouse extends House
{  
    public function openDoor(): void
    {
        // Open the door...
    }
    
    public function getRooms(): array
    {
        return [
            'Bedroom One',
            'Bedroom Two',
            'Bathroom',
            'Living Room',
            'Kitchen',
        ];  
    }
}
```

```php
// This will not work:
$house = new House();

// This will work:
$house = new MyHouse();
```

You might have noticed that in the `House` class that we have declared an abstract public method called `openDoor()`. This is basically allowing us to define a method's signature that a child class should include in a similar way as we would with an interface. This is really handy if you want to share some functionality with your child classes but also enforce that they include their own implementations of some methods.

In this particular instance, a child class could override the `getRooms()` and `hasGarden()` methods as usual, but wouldn't be required to include them. To show this, we've overridden the `getRooms()` method to show how we could change it's behaviour in the child class.

## How to Decide Which to Use

It's really going to depend on what your goal is. To keep to our house analogy, if you're creating blueprints that can be used later to design different types of houses then you need an interface.

If you've built a house and now you need to make copies with customization then you need an abstract class.

Let me give you some examples:

### When to Use an Interface

To help us understand when to use an interface, let's look at an example. Let's say that we have a `ConstructionCompany` class that includes a `buildHome()` method that looks like this:

```php
class ConstructionCompany
{
    public function buildHome($home)
    { 
        // Build the home here...
	  
        return $home;
    }
}
```

Now, let's say that we have 3 different classes that we want to be able to buld and pass to the `buildHome()` method:

1. `class MyHouse implements HomeInterface extends House`
1. `class MyCaravan implements HomeInterface`
1. `class MyFlat implements HomeInterface`

As we can see, the `MyHouse` class extends the `House` abstract class; and this makes total sense from a conceptual point of view because the house is a house. However, it wouldn't make sense for the `MyCaravan` or `MyFlat` class to extend from the abstract class because neither of them are houses.

So, because our construction company is able to build houses, caravans and flats, this rules out us type hinting the `$home` parameter in the `buildHome()` method to be an instance of `House`.

However, this would be a perfect place for us to type hint our method to only allow classes that implement the `HomeInterface` to be passed. As an example, we could update the method to be:

```php
class ConstructionCompany
{
    public function buildHome(HomeInterface $home)
    { 
        // Build the home here...
	  
        return $home;
    }
}
```

As a result of doing this, we can be sure that whether we pass a house, caravan or flat, that our `ConstructionCompany` class will have the information it needs because the home object passed in will always contain the necessary methods that we need.

You might have also thought to yourself "why don't we just create a `Home` abstract class instead of an interface?". However, it's important to remember that PHP only supports single inheritance and that a class can't extend more than one parent class. So, this would make it pretty difficult if you ever wanted to extend one of your classes in the future.

### When to Use an Abstract Class

Let's take a scenario similar to our example above. Let's imagine that we have a `HouseConstructionCompany` that's similar to our `ConstructionCompany`. But, in this example, we'll assume that the `HouseConstructionCompany` only build houses and nothing else.

Because we know that we only need to be able to build houses, we could type hint our method to only accept classes that extend the `House` abstract class. This can be really useful because we can always be sure that we're not passing any other types of homes to the method that the construction company doesn't build. For example:

```php
class HouseConstructionCompany
{
    public function buildHouse(House $house)
    { 
        // Build the house here...
	  
        return $house;
    }
}
```

## Conclusion

Hopefully, this post will have given you an insight into the differences between interfaces and abstract classes in PHP. It should have also given you a brief overview of the different scenarios when you should use either one of them.

If this post helped you out, I'd love to hear about it. Likewise, if you have any feedback to improve this post, I'd also love to hear that too.

If you're interested in getting updated each time I publish a new post, feel free to [sign up for my newsletter here](https://ashallendesign.co.uk/blog).

For any of my Laravel developer readers who are looking for any further reading around interfaces, you can read about how you can use interfaces to [use the strategy pattern in Laravel](https://ashallendesign.co.uk/blog/using-the-bridge-pattern-in-laravel) here.

A massive thanks to <a href="https://www.linkedin.com/in/james-mahy-84524615/" target="_blank" rel="noopener noreferrer">James Mahy</a>, <a href="https://www.linkedin.com/in/aditya-kadam-77a594134/" target="_blank" rel="noopener noreferrer">Aditya Kadam</a> and <a href="https://www.linkedin.com/in/andrew-palfrey/" target="_blank" rel="noopener noreferrer">Andrew Palfrey</a> for proofreading this article and giving me feedback on it! I'd recommend checking out a cool social network that James is building: <a href="https://sosa.net/" target="_blank" rel="noopener noreferrer">SoSa</a>, a fun, friendly and privacy first community that makes it easy and fun to socialise online!

Also a huge thanks to <a href="https://www.linkedin.com/in/jessica-pickup-481030186/" target="_blank" rel="noopener noreferrer">Jess Pickup</a> for creating another cool blog post image as usual!

Keep on building awesome stuff! 🚀