Interfaces and Abstract Classes
Tags: php
Published: 2019-04-19 15:20:10

---
title: Interfaces and Abstract Classes
published: true
description: A pratical approach about Interfaces and Abstract Classes
tags: php
cover_image: https://thepracticaldev.s3.amazonaws.com/i/3henlvgnv93ws3exfle4.png
---

For most people I've talked on my journey through software development, *abstraction* always brings the idea of *code reuse*. You might think about company and person objects, both have names, addresses, phone contacts, and so on. They both share common attributes and maybe even common behavior. You can define an abstract base class named `Entity` and then create two concrete classes, `Person` and `Company`, extended from `Entity`.

Let's take a step back, imagine basic PHP types, boolean, integer, float, objects and all the ways you are able to work with them. Everyone knows or at least should know, the expected behavior of those types. I mean, if you create an integer variable, you know what kind of value to expect and what kind of operations you can perform with it. 

> Every type has its own stable behavior.

A programming language cares itself about the unchangeable behavior of its essential types. The same idea applies when we are defining abstract classes and their concrete implementations.

## Abstract Classes

When extending from other classes, we are creating new *data types*. The code snippets below define a new child class `ArrayCache`, which **is a** `AbstractCache` class. Thus, the child class is a specification that will inherit all of the parent's non-private properties and methods. **The client code still expects them to behave exactly as their parent does**:

```php
abstract class AbstractCache
{
    abstract public function get(string $key)
    { }

    abstract public function set(string $key, $value)
    { }
}
```

```php
class ArrayCache extends AbstractCache
{
    protected $items;

    public function get(string $key)
    {
        return $this->item[$key];
    }

    public function set(string $key, $value)
    {
        $this->item[$key] = $value;
    }
}
```

According to Liskov Substitution Principle, we can use these sub-types, without any special knowledge, only by reading the parent class public interface.

All concrete implementations from the same abstract base class should obey the abstract class interfaces. **When using inheritance, it is our responsibility to respect the parent class interface.** When working with inheritance, try to keep the hierarchy short, no more than three levels. Also, remember that if there is some code in the *parent* class that you are using from the client one as `parent::method()`, you must care about the returned values as well.

> When we provide public methods we are saying: "With this data type you can do this and it will behave in this particular way."

You can think of abstraction as taking out unnecessary details to describe something in simpler terms in order to focus only on important aspects of the current context. Encapsulation plays the main role here, as a technique used to hide some state and behavior from the outside world. Client code can interact with it through its methods, but cannot access its state directly.

In other words:

> A public interface is a set of rules, that defines the way in which we can interact with an object.

## Interfaces

When you are trying to enforce the same behavior for different types, you may want to take advantage of *Interfaces*.

An interface in PHP can contain methods and constants, but can't contain any variables. All methods must be public and have no implementation. Also, an interface can be inherited from another by *extends* keyword. Even though classes can inherit from multiple interfaces, that can't implement two interfaces that share the same method names, it would cause ambiguity.

Hence, we usually use abstraction for code reuse when defining a hierarchy of data types. As for interfaces, its common use is to enforce certain behavior.

For instance, we want to make sure that those two types, `Company` and `Person` can be cached by providing its own key and its own value:

```php
interface Cacheable
{
    public function getCacheKey();
    public function getCacheValue();
}
```

We have to create the `Company` class and the methods imposed by `Cacheable` interface:

```php
class Company extends Entity implements Cacheable
{
    public function getCacheKey()
    {
        return 'company_' . $this->id;
    }

    public function getCacheValue()
    {
       return [
           'name' => $this->name,
           'phone' => $this->phone,
           'address' => $this->address,
           'foundation_date' => $this->foundation_date
       ];
    }
}
```

The same for `Person` class:

```php
class Person extends Entity implements Cacheable
{
    public function getCacheKey()
    {
        return 'person_' . $this->id;
    }

    public function getCacheValue()
    {
       return [
           'name' => $this->name,
           'phone' => $this->phone,
           'address' => $this->address,
           'birth_date' => $this->birth_date
       ];
    }
}
```

With this *inverted* approach, all caching logic is encapsulated in a *cacheable* class. Every class must define its own rules, how it should be stored in the cache. The `Cache` class knows nothing about these details, it trusts `Cacheable` objects and calls their `getCacheKey` and `getCacheData` methods.

> This blind trust is the main idea of using interfaces. We are establishing a contract that must be honored by both sides.

We can now redefine our `ArrayCache` like these:

```php
class AbstractCache extends AbstractCache
{
    protected $items;

    abstract public function get(Cacheable $entity)
    {
        $key = $entity->getCacheKey();
        return $this->item[$key];
    }
    
    abstract public function set(Cacheable $entity, $value)
    {
        $key = $entity->getCacheKey();
        $data = $entity->getCacheValue();

        $this->item[$key] = $value;
    }
}
``` 

Keep in mind that interfaces don't define a new type, they describe an aspect of a type.

## References

- https://daylerees.com/php-pandas-interfaces/
- https://daylerees.com/php-interfaces-explained/
- https://leanpub.com/phpoopway