Eine Integration ist kein technisches Detail mehr, wenn ihre Felder, Fehlercodes und Zugriffsregeln in Controllern, Anwendungsservices, Modellen und Geschäftsprozessen auftauchen. Ab diesem Punkt erfordert ein Anbieterwechsel, ein API-Update oder die Bearbeitung eines externen Vorfalls Änderungen in Teilen der Anwendung, die dieses System nicht kennen sollten.
Externe Integrationen in PHP zu isolieren bedeutet, eine klare Grenze zu ziehen: Die Domäne drückt in ihrer eigenen Sprache aus, was sie benötigt, und eine Infrastrukturschicht übersetzt diesen Bedarf in das konkrete Protokoll, Format und Verhalten des Anbieters. Es geht nicht darum, eine API hinter einer Klasse mit einem anderen Namen zu verstecken, sondern darum zu verhindern, dass deren Entscheidungen die gesamte Anwendung prägen.
Wann eine Integration die Anwendung bereits verunreinigt

Die Kopplung wächst meist schrittweise. Ein Team nutzt eine API aus einem Controller heraus, um eine dringende Auslieferung zu ermöglichen; anschließend verwendet ein anderer Ablauf denselben Client wieder; schließlich werden Antwort-Arrays und SDK-Ausnahmen zu impliziten Abhängigkeiten der Geschäftslogik.
- Use Cases empfangen oder liefern Arrays mit Feldnamen des Anbieters.
- Die Geschäftslogik vergleicht externe Codes wie
ERR_42oderPENDING_REVIEW. - Controller, Commands und Queue-Jobs erstellen HTTP-Anfragen direkt.
- Ausnahmen des externen SDK werden außerhalb der Infrastruktur abgefangen.
- Eine Änderung von Zugangsdaten, Endpoints oder Versionen macht Änderungen an mehreren Modulen erforderlich.
- Tests der Domäne benötigen echte Verbindungen, Tokens oder simulierte Antworten des Anbieters.
Diese Signale bedeuten nicht, dass eine vollständige Neuentwicklung begonnen werden muss. Sie weisen jedoch darauf hin, dass es sinnvoll ist, die Integration nach ihrem Risiko zu priorisieren: Geschäftskritikalität, Häufigkeit der Änderungen durch den Anbieter, Anzahl interner Verbraucher, Sensibilität der Daten und Schwierigkeit, sich von einem Fehler zu erholen.
Verträge aus der Sprache des Geschäfts definieren
Der interne Vertrag, auch Port genannt, muss eine Fähigkeit beschreiben, die die Anwendung benötigt, und keine Nachbildung des Operationskatalogs einer externen API sein. Beispielsweise kann eine Buchungsanwendung „eine Buchung anfordern“, „ihren Status abfragen“ und „sie stornieren“ müssen. Die Domäne muss nicht wissen, dass ein Anbieter XML, OAuth, eine numerische Kennung oder eine bestimmte Retry-Konvention verwendet.
Ein Port kann als PHP-Interface ausgedrückt werden:
interface ReservationGateway
{
public function request(ReservationRequest $request): ReservationResult;
public function status(ReservationReference $reference): ReservationStatus;
public function cancel(ReservationReference $reference): void;
}Die Typen des Vertrags müssen zur internen Sprache gehören. ReservationRequest enthält die für die Geschäftsentscheidung erforderlichen Daten; es sollte keine Authentifizierungsfelder, HTTP-Header oder vom Anbieter übernommene Namen enthalten. Ebenso kann eine interne Referenz die externe Identität kapseln, ohne sie in allen Use Cases dominant zu machen.
Die Bestandteile einer Integrationsgrenze
Port, Adapter und internes DTO
Der Port ist das Interface, das die Anwendung nutzt. Der Adapter ist die Implementierung, die mit dem externen System kommuniziert. Dazwischen übertragen interne DTOs Daten in einer für die Anwendung stabilen Struktur.
Der Adapter übersetzt in beide Richtungen: Er wandelt das interne DTO in eine spezifische Anfrage um und normalisiert die Antwort zu einem Ergebnis, das die Domäne interpretieren kann. Wenn der Anbieter guest_count durch travellers ersetzt, muss die Änderung in diesem Adapter enthalten bleiben.
Konfiguration, Zugangsdaten und Transport
Endpoints, Tokens, Timeouts, Zertifikate und Retry-Richtlinien sind Belange der Infrastruktur. Sie müssen über Konfiguration injiziert und außerhalb von Entitäten und Domain-Services gehalten werden. Es ist außerdem sinnvoll, den HTTP-Client oder das SDK vom Adapter zu trennen: Das erleichtert den Austausch von Bibliotheken, die Erfassung von Telemetrie und das Testen des Mappings, ohne vom tatsächlichen Transport abhängig zu sein.
Übersetzung von Fehlern und ungewissen Zuständen
Nicht alle Fehler werden gleich behandelt. Ein vom Anbieter abgelehnter Validierungsfehler kann für den Benutzer behebbar sein; ein Authentifizierungsfehler erfordert operatives Eingreifen; ein Timeout kann einen ungewissen Zustand hinterlassen, weil der Anbieter die Anfrage möglicherweise verarbeitet hat.
Der interne Vertrag muss diese Unterschiede darstellen, ohne fremde Ausnahmen durchzulassen. Beispielsweise kann der Adapter eine Validierungsantwort in ReservationRejected, ein vorübergehendes Problem in TemporaryUnavailable und ein Timeout nach dem Senden der Anfrage in UnknownSubmissionState umwandeln. Letzteres darf nicht als einfacher Fehler behandelt werden: Es kann eine spätere Abfrage über einen Idempotenzschlüssel oder einen operativen Abgleich erfordern.
Fehler zu übersetzen bedeutet nicht, Details zu löschen. Protokollieren Sie die Korrelationskennung, die technische Ursache und die relevante Antwort sicher, ohne Geheimnisse oder sensible Daten dem Benutzer preiszugeben.
Beispiel für die Kapselung eines Buchungsdienstes
Nehmen wir an, ein Anbieter verlangt eine JSON-Anfrage mit Datumsangaben in einem bestimmten Format, einem eigenen Hotelcode und einem Autorisierungsheader. Der interne Use Case sollte diese Anfrage nicht erstellen. Er erhält eine Buchungsanfrage, wendet seine Regeln an und ruft ReservationGateway auf.
Der Adapter ExternalReservationAdapter übernimmt die spezifischen Aufgaben:
- Er wandelt die interne Unterkunftskennung in den vom Anbieter erkannten Code um.
- Er formatiert Datumsangaben, Gäste und Präferenzen gemäß dem externen Vertrag.
- Er fügt Zugangsdaten und einen Idempotenzschlüssel hinzu.
- Er interpretiert HTTP-Codes, Fehlerantworten und eigene Statuswerte.
- Er gibt eine interne Referenz und einen internen Status zurück.
Die Anwendung behält die Regel, wann eine Buchung akzeptabel ist; der Adapter behält die Regel, wie sie bei diesem Anbieter angefragt wird. Kommt ein zweiter Anbieter hinzu, kann derselbe Port implementiert werden, sofern die geschäftliche Fähigkeit gleichwertig ist. Ist sie es nicht, kann das Erzwingen eines gemeinsamen Interface wichtige Unterschiede verbergen und mehrdeutige Entscheidungen schaffen.
So extrahieren Sie eine bereits gekoppelte Integration
Eine sichere Migration erfordert nicht, die Weiterentwicklung des Produkts anzuhalten. Beginnen Sie mit einer Bestandsaufnahme: Suchen Sie direkte Aufrufe, SDK-Klassen, externe Formate, durchgelassene Ausnahmen und Verbraucher. Identifizieren Sie zuerst die kritischen Pfade oder jene, die sich am häufigsten ändern.
- Führen Sie eine Fassade ein: Erstellen Sie den Port und einen ersten Adapter, der vorübergehend Teile des bestehenden Clients wiederverwenden kann.
- Migrieren Sie Verbraucher pro Ablauf: Ersetzen Sie die direkten Aufrufe eines Use Cases nach dem anderen. Vermeiden Sie es, zwei unterschiedliche Interpretationen desselben Fehlers beizubehalten.
- Zentralisieren Sie das Mapping: Entfernen Sie Umwandlungen externer Felder und Codes aus Controllern, Services und Templates.
- Fügen Sie Observability hinzu: Erfassen Sie Latenz, Ergebnisse, normalisierte Fehler und die Korrelation zwischen interner Anfrage und externem Aufruf.
- Entfernen Sie den direkten Zugriff: Wenn keine Verbraucher mehr vorhanden sind, beschränken oder entfernen Sie den exponierten Client, um Regressionen zu vermeiden.
Während der Umstellung darf die Fassade nicht zu einem generischen Container für SDK-Methoden werden. Ihr Zweck besteht darin, eine nützliche und stabile Grenze zu definieren, nicht darin, die Kopplung in einen anderen Ordner zu verlagern.
Tests und Kriterien zur Validierung der Isolierung
Tests der Domäne sollten Doubles des Ports verwenden. So überprüfen sie Geschäftsentscheidungen ohne Netzwerk, Zugangsdaten oder zufällige Verhaltensweisen des Anbieters. Die Tests des Adapters hingegen müssen das Mapping von Anfragen, Antworten und Fehlern gegen eine kontrollierte Umgebung, einen simulierten Server oder vom externen System dokumentierte Verträge prüfen.
Das Ergebnis ist überprüfbar, wenn diese Kriterien erfüllt sind:
- Eine Änderung von Format, Endpoint oder SDK konzentriert sich auf den Adapter und dessen Konfiguration.
- Use Cases hängen von internen Verträgen ab, nicht von HTTP-Clients oder externen Typen.
- Ausnahmen und Codes des Anbieters überschreiten die Grenze nicht.
- Ungewisse Zustände haben eine explizite Behandlung, einschließlich Idempotenz oder späterer Abfrage, wenn dies erforderlich ist.
- Geschäftstests werden mit Doubles ausgeführt, und Integrationstests validieren die tatsächliche Übersetzung.
Häufige Fehler vor der Einbindung eines weiteren Anbieters

Vorzeitige Abstraktion ist ein Risiko: Erstellen Sie keine komplexe Hierarchie für eine einzige stabile Integration ohne tatsächliche Anforderungen an Austauschbarkeit. Auch das entgegengesetzte Extrem scheitert: Die gesamte externe API in einem internen Interface nachzubilden, führt dazu, dass die Domäne deren Komplexität übernimmt.
Bestätigen Sie vor der Integration, welche Fähigkeit das Geschäft benötigt, wem welche Daten gehören, welche Fehler handlungsrelevant sind, wie doppelte Vorgänge vermieden werden und was geschieht, wenn keine Antwort eintrifft. Definieren Sie den Port anhand dieser Entscheidungen, implementieren Sie den Adapter als Übersetzer und halten Sie externe Besonderheiten am Rand. Diese Disziplin ermöglicht es, externe Integrationen in PHP zu isolieren, ohne jede Anbieteränderung zu einer bereichsübergreifenden Änderung der Anwendung zu machen.



