Приведу пример на коленке. Хотим, например, написать абстрактную файловую систему. Для начала, определим интерфейс, для ФС:
interface FileSystemInterface {
  public function write($file, $data);
  public function read($file);
}
Затем, хочу реализацию интерфейса ФС для работы с файликами:
class OSFileSystem implements FileSystemInterface {
  public function write($file, $data) {
     // открываем файлик, пишем данные
  }
  public function read($file) {
    // открываем файлик, возвращаем данные
  }
}
Вдруг, кому-то захотелось файловую систему в облаке. Окей, не проблема, реализуем это:
class CloudFileSystem implements FileSystemInterface {
  public function write($file, $data) {
     // открываем соединение с облаком, пишем данные
  }
  public function read($file) {
    // открываем соединение с облаком, возвращаем данные
  }
}
Пусть у нас есть кой-то код, работающий с файловой системой, назовем его "Хранилище файлов". Пусть он выглядит примерно так:
class FileStorage {
  protected $Fs;
  
  public function __construct(FileSystemInterface $Fs) {
    $this->Fs = $Fs;
  }  
  public function saveFile() {
    $this->Fs->write('file.txt', 'file data');
  }
  public function getFile() {
    return $this->Fs->read('file.txt', 'file data');
  }
}
Отлично! Теперь мы можем хранилищу файлов отдать любой объект с реализованным интерфейсом 
FileSystemInterface. Пример:
// Хранилище файлов работает с файловой системой ОС:
$FS = new OSFileSystem();
$FileStorage = new FileStorage($Fs);
$FileStorage->getFile();
// Хранилище файлов работает с файловой системой в облаке:
$FS = new CloudFileSystem();
$FileStorage = new FileStorage($Fs);
$FileStorage->getFile();
Использование интерфейса, в данном случае. позволяет нам писать только реализацию работы файловой системы, а бизнес-логика, работающая с файловой системой никак не меняется, она знает, что в любом случае файловая система реализует интерфейс 
FileSystemInterface и может без опаски использовать методы этого интерфейса.