W3docs

Objektorientierte Programmierung mit PHP Interfaces

PHP Interfaces sind ein grundlegender Bestandteil der OOP: Verträge, die festlegen, welche Methoden eine Klasse bereitstellen muss.

Ein Interface ist ein Vertrag, der die Methoden auflistet, die eine Klasse bereitstellen muss, ohne anzugeben, wie diese Methoden funktionieren. Es ermöglicht nicht verwandten Klassen, sich auf eine gemeinsame Menge von Verhaltensweisen zu einigen, sodass der restliche Code vom Vertrag und nicht von einer bestimmten Klasse abhängen kann. Dieses Kapitel behandelt die Deklaration von Interfaces, ihre Implementierung, die Verwendung von Konstanten, das Erweitern und Kombinieren von Interfaces sowie häufige Fallstricke.

Wenn Sie noch neu bei Objekten sind, lesen Sie zuerst PHP Klassen und Objekte und Was ist OOP in PHP.

Was ist ein Interface in PHP?

Ein Interface definiert eine Menge öffentlicher Methoden-Signaturen — Namen, Parameter und (optional) Rückgabetypen — aber keine Methodenrümpfe. Jede Klasse, die das Interface implementiert, verspricht, für jede dieser Methoden einen konkreten Rumpf bereitzustellen. Tut sie es nicht, wirft PHP einen fatalen Fehler.

Da das Interface nur angibt, was eine Klasse tun kann und niemals wie, können Sie eine Implementierung gegen eine andere austauschen, ohne den Code zu ändern, der sie verwendet. Diese Entkopplung ist der eigentliche Zweck.

<?php
interface Logger {
  public function log(string $message): void;
}

Wichtige Regeln für Interface-Member:

  • Alle Methoden sind implizit public und abstract — Sie können ihnen keine Rümpfe geben und können sie nicht als private oder protected markieren.
  • Ein Interface kann Konstanten deklarieren, aber keine Eigenschaften.
  • Eine Klasse signalisiert mit dem Schlüsselwort implements, dass sie den Vertrag erfüllt.

Warum Interfaces verwenden?

  • Verträge. Sie garantieren, dass jede implementierende Klasse eine vereinbarte API bereitstellt, sodass Aufrufer genau wissen, welche Methoden verfügbar sind.
  • Lose Kopplung. Code kann gegen das Interface (Logger) statt gegen eine konkrete Klasse (FileLogger) geschrieben werden, sodass Implementierungen frei ausgetauscht werden können — ein echter Datei-Logger in der Produktion, ein gefälschter in Tests.
  • Mehrere Typen. Anders als bei der Klassenvererbung kann eine Klasse viele Interfaces implementieren und dadurch mehrere Rollen gleichzeitig einnehmen.
  • Polymorphismus. Verschiedene Objekte, die ein Interface teilen, können überall dort austauschbar verwendet werden, wo dieses Interface erwartet wird.

Ein Interface implementieren

Verwenden Sie das Schlüsselwort implements gefolgt vom Interface-Namen und geben Sie dann für jede Methode, die das Interface deklariert, einen Rumpf an.

<?php
interface Logger {
  public function log(string $message): void;
}

class ConsoleLogger implements Logger {
  public function log(string $message): void {
    echo "[LOG] {$message}\n";
  }
}

$logger = new ConsoleLogger();
$logger->log('App started');
// Output: [LOG] App started

ConsoleLogger erfüllt den Logger-Vertrag, sodass Sie überall dort, wo Ihr Code einen Logger erwartet, einen ConsoleLogger übergeben können.

Type Hinting gegen ein Interface

Der größte Vorteil entsteht, wenn Sie das Interface als Type Hint verwenden statt einer konkreten Klasse. Die folgende Funktion funktioniert mit jedem Logger, sodass Implementierungen ohne Umschreiben ausgetauscht werden können.

<?php
interface Logger {
  public function log(string $message): void;
}

class ConsoleLogger implements Logger {
  public function log(string $message): void {
    echo "[LOG] {$message}\n";
  }
}

class SilentLogger implements Logger {
  public function log(string $message): void {
    // intentionally does nothing
  }
}

function runJob(Logger $logger): void {
  $logger->log('Job finished');
}

runJob(new ConsoleLogger()); // Output: [LOG] Job finished
runJob(new SilentLogger());  // Output: (nothing)

Mehrere Interfaces implementieren

Eine Klasse kann mehrere Interfaces gleichzeitig implementieren, indem deren Namen durch Kommas getrennt werden. So umgeht PHP das Fehlen von Mehrfachklassenvererbung.

<?php
interface Drawable {
  public function draw(): string;
}

interface Serializable {
  public function toArray(): array;
}

class Circle implements Drawable, Serializable {
  public function __construct(private float $radius) {}

  public function draw(): string {
    return "Circle(r={$this->radius})";
  }

  public function toArray(): array {
    return ['type' => 'circle', 'radius' => $this->radius];
  }
}

$c = new Circle(2.5);
echo $c->draw() . "\n";          // Output: Circle(r=2.5)
echo json_encode($c->toArray()); // Output: {"type":"circle","radius":2.5}

Interface-Konstanten

Interfaces können Konstanten enthalten, die jede implementierende Klasse erbt. Sie sind nützlich für gemeinsame, feste Werte, die zum Vertrag gehören.

<?php
interface HttpStatus {
  const OK = 200;
  const NOT_FOUND = 404;
}

class Response implements HttpStatus {
  public function notFound(): int {
    return self::NOT_FOUND;
  }
}

$r = new Response();
echo $r->notFound();        // Output: 404
echo HttpStatus::OK;        // Output: 200

Interfaces erweitern

Ein Interface kann mit extends auf einem anderen aufbauen, und anders als bei Klassen kann ein Interface mehrere Interfaces gleichzeitig erweitern. Eine Klasse, die das abgeleitete Interface implementiert, muss alle geerbten Methoden erfüllen.

<?php
interface Readable {
  public function read(): string;
}

interface Writable {
  public function write(string $data): void;
}

interface ReadWrite extends Readable, Writable {}

class Memory implements ReadWrite {
  private string $buffer = '';

  public function read(): string {
    return $this->buffer;
  }

  public function write(string $data): void {
    $this->buffer .= $data;
  }
}

$m = new Memory();
$m->write('hello ');
$m->write('world');
echo $m->read(); // Output: hello world

Auf ein Interface prüfen

Verwenden Sie den instanceof-Operator, um zu bestätigen, dass ein Objekt einen bestimmten Vertrag erfüllt, bevor Sie seine Methoden aufrufen.

<?php
interface Logger {
  public function log(string $message): void;
}

class ConsoleLogger implements Logger {
  public function log(string $message): void {
    echo $message . "\n";
  }
}

$obj = new ConsoleLogger();
var_dump($obj instanceof Logger); // Output: bool(true)

Interface vs. abstrakte Klasse

Sie überschneiden sich, lösen aber unterschiedliche Probleme:

InterfaceAbstrakte Klasse
MethodenrümpfeNein (nur Signaturen)Ja (kann konkrete + abstrakte mischen)
EigenschaftenNein (nur Konstanten)Ja
Wie viele pro KlasseViele (implements A, B)Eine (extends A)
Verwenden wennNicht verwandte Klassen teilen eine FähigkeitVerwandte Klassen teilen Code und Zustand

Greifen Sie auf ein Interface zurück, um eine Fähigkeit zu beschreiben; greifen Sie auf eine abstrakte Klasse zurück, um eine teilweise Implementierung unter verwandten Klassen zu teilen. Wenn Sie Methodenrümpfe über nicht verwandte Klassen hinweg teilen müssen, lesen Sie PHP Traits.

Häufige Fallstricke

  • Eine Methode fehlt. Wenn auch nur eine Interface-Methode nicht implementiert wird, löst dies bei der Klassendeklaration einen fatalen Fehler aus.
  • Sichtbarkeit einschränken. Interface-Methoden sind public; Sie können sie nicht als protected oder private implementieren.
  • Die Signatur ändern. Die Parameter und der Rückgabetyp der implementierenden Methode müssen mit dem Interface kompatibel bleiben, sonst wirft PHP einen Fehler.
  • Eigenschaften erwarten. Interfaces deklarieren Verhalten, keine Daten — sie können keine Eigenschaften enthalten, nur Konstanten.

Fazit

Interfaces ermöglichen es Ihnen, gegen einen Vertrag statt gegen eine konkrete Klasse zu programmieren: Sie definieren, was eine Klasse tun muss, unterstützen mehrere Implementierungen und erleichtern Polymorphismus, Tests und Refactoring erheblich. Kombinieren Sie sie mit Vererbung und Traits, um flexible, wartbare PHP-Anwendungen zu entwerfen.

Übung

Übung
Was ist laut der Seite von W3Docs der primäre Verwendungszweck von PHP Interfaces?
Was ist laut der Seite von W3Docs der primäre Verwendungszweck von PHP Interfaces?
Was this page helpful?