W3docs

Programmation orientée objet avec les interfaces PHP

Les interfaces PHP définissent un contrat de méthodes que les classes doivent implémenter, favorisant le couplage faible et le polymorphisme en POO.

Une interface est un contrat qui liste les méthodes qu'une classe doit fournir, sans préciser comment ces méthodes fonctionnent. Elle permet à des classes non liées de s'accorder sur un ensemble commun de comportements, de sorte que le reste de votre code peut dépendre du contrat plutôt que d'une classe spécifique. Ce chapitre explique comment déclarer des interfaces, les implémenter, utiliser des constantes, étendre et combiner des interfaces, ainsi que les pièges courants à éviter.

Si vous débutez avec les objets, lisez d'abord Classes et objets PHP et Qu'est-ce que la POO en PHP.

Qu'est-ce qu'une interface en PHP ?

Une interface définit un ensemble de signatures de méthodes publiques — noms, paramètres et (facultativement) types de retour — mais aucun corps de méthode. Toute classe qui implémente l'interface s'engage à fournir un corps concret pour chacune de ces méthodes. Si elle ne le fait pas, PHP génère une erreur fatale.

Comme l'interface indique uniquement ce que peut faire une classe et jamais comment, vous pouvez remplacer une implémentation par une autre sans modifier le code qui les utilise. Ce découplage est tout l'intérêt.

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

Règles clés pour les membres d'une interface :

  • Toutes les méthodes sont implicitement publiques et abstraites — vous ne pouvez pas leur donner de corps, et vous ne pouvez pas les marquer private ou protected.
  • Une interface peut déclarer des constantes, mais pas de propriétés.
  • Une classe signale qu'elle remplit le contrat avec le mot-clé implements.

Pourquoi utiliser des interfaces ?

  • Contrats. Elles garantissent que toute classe implémentante expose une API convenue, afin que les appelants sachent exactement quelles méthodes sont disponibles.
  • Couplage faible. Le code peut être écrit pour l'interface (Logger) plutôt que pour une classe concrète (FileLogger), ce qui permet de changer librement d'implémentation — un vrai logger de fichier en production, un faux en tests.
  • Types multiples. Contrairement à l'héritage de classes, une classe peut implémenter plusieurs interfaces, lui permettant de jouer plusieurs rôles à la fois.
  • Polymorphisme. Différents objets partageant une interface peuvent être utilisés de manière interchangeable partout où cette interface est attendue.

Implémenter une interface

Utilisez le mot-clé implements suivi du nom de l'interface, puis fournissez un corps pour chaque méthode déclarée par l'interface.

<?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 respecte le contrat Logger, donc partout où votre code attend un Logger, vous pouvez passer un ConsoleLogger.

Indication de type avec une interface

Le plus grand avantage vient quand vous indiquez le type de l'interface plutôt que d'une classe concrète. La fonction ci-dessous fonctionne avec n'importe quel Logger, ce qui vous permet de changer d'implémentation sans la réécrire.

<?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)

Implémenter plusieurs interfaces

Une classe peut implémenter plusieurs interfaces à la fois en séparant leurs noms par des virgules. C'est ainsi que PHP contourne l'absence d'héritage multiple de classes.

<?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}

Constantes d'interface

Les interfaces peuvent contenir des constantes, que toute classe implémentante hérite. Elles sont utiles pour les valeurs fixes partagées qui appartiennent au contrat.

<?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

Étendre des interfaces

Une interface peut s'appuyer sur une autre avec extends, et contrairement aux classes, une interface peut étendre plusieurs interfaces à la fois. Une classe implémentant l'interface enfant doit satisfaire toutes les méthodes héritées.

<?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

Vérifier une interface

Utilisez l'opérateur instanceof pour confirmer qu'un objet respecte un contrat donné avant d'appeler ses méthodes.

<?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. classe abstraite

Elles se recoupent mais résolvent des problèmes différents :

InterfaceClasse abstraite
Corps de méthodesNon (signatures uniquement)Oui (peut mélanger concret + abstrait)
PropriétésNon (constantes uniquement)Oui
Combien par classePlusieurs (implements A, B)Une (extends A)
À utiliser quandDes classes non liées partagent une capacitéDes classes liées partagent du code et un état

Préférez une interface pour décrire une capacité ; préférez une classe abstraite pour partager une implémentation partielle entre classes liées. Si vous devez partager des corps de méthodes entre classes non liées, consultez PHP Traits.

Pièges courants

  • Méthode manquante. Oublier d'implémenter ne serait-ce qu'une méthode d'interface déclenche une erreur fatale à la déclaration de la classe.
  • Réduire la visibilité. Les méthodes d'interface sont publiques ; vous ne pouvez pas les implémenter en protected ou private.
  • Modifier la signature. Les paramètres et le type de retour de la méthode implémentante doivent rester compatibles avec l'interface, sinon PHP génère une erreur.
  • S'attendre à des propriétés. Les interfaces déclarent des comportements, pas des données — elles ne peuvent pas contenir de propriétés, seulement des constantes.

Conclusion

Les interfaces vous permettent de programmer selon un contrat plutôt qu'une classe concrète : elles définissent ce qu'une classe doit faire, prennent en charge plusieurs implémentations et facilitent considérablement le polymorphisme, les tests et la refactorisation. Combinez-les avec l'héritage et les traits pour concevoir des applications PHP flexibles et maintenables.

Pratique

Pratique
Quelle est l'utilisation principale des interfaces PHP selon la page de W3Docs ?
Quelle est l'utilisation principale des interfaces PHP selon la page de W3Docs ?
Was this page helpful?