← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Ports & Adapters (PHP Worked Example)

architecture PHP 7.0+ Advanced

Also Known As

hexagonal architecture PHP ports and adapters Alistair Cockburn

TL;DR

Hexagonal Architecture in PHP — the application core exposes ports (interfaces), and adapters implement them for HTTP, CLI, databases, and external services.

Explanation

Ports & Adapters (Alistair Cockburn, 2005) defines the application as a hexagon with ports on each face. Input ports are interfaces the application offers (CreateOrderUseCase, FindUserQuery). Output ports are interfaces the application requires (OrderRepository, EmailGateway). Adapters implement ports for specific technologies: HttpAdapter drives input ports; DoctrineAdapter implements output ports. The core never depends on adapters — the dependency always points inward. This enables testing the core without any infrastructure, and swapping adapters without touching the core.

Common Misconception

Ports & Adapters requires a complex folder structure — the pattern is about dependency direction, not folder layout; a simple PHP project can implement it with just interfaces and implementations in any structure.

Why It Matters

A PHP application where controllers call Eloquent models directly cannot be tested without a database — ports & adapters makes the entire application core testable with pure PHP, no infrastructure needed.

Common Mistakes

  • Output port interface in the infrastructure layer — interfaces belong to the application core.
  • Application core importing Doctrine or Eloquent classes — the core must not know about adapters.
  • One port per use case — keep ports focused; CreateOrderPort not a generic OrderPort with 20 methods.
  • Not testing through ports — tests should call use cases via ports, not internal methods.

Code Examples

✗ Vulnerable
// Core directly depends on infrastructure — tightly coupled:
class CreateOrderUseCase {
    public function __construct(
        private \Doctrine\ORM\EntityManager $em, // Infrastructure in core!
        private \Swift_Mailer $mailer,            // Infrastructure in core!
    ) {}
    // Cannot test without Doctrine and Swift
}
✓ Fixed
// Core depends only on own interfaces (ports):
interface OrderRepository {   // Output port — in core
    public function save(Order $order): void;
}
interface EmailGateway {       // Output port — in core
    public function sendConfirmation(Order $order): void;
}

class CreateOrderUseCase {     // Core — no infrastructure imports
    public function __construct(
        private OrderRepository $orders,   // Port — not Doctrine
        private EmailGateway    $email,    // Port — not SwiftMailer
    ) {}
}

// Adapters in infrastructure layer:
class DoctrineOrderRepository implements OrderRepository { /* ... */ }
class SwiftEmailGateway        implements EmailGateway    { /* ... */ }
// Tests inject InMemoryOrderRepository — no DB needed

Added 16 Mar 2026
Edited 22 Mar 2026
Views 32
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 1 ping T 2 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S
No pings yesterday
Perplexity 8 Amazonbot 7 Google 6 Ahrefs 2 Unknown AI 2 SEMrush 2
crawler 25 crawler_json 2
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: High
⚡ Quick Fix
Define ports (interfaces) in your domain/application layer — adapters implement them in the infrastructure layer; the domain never imports from infrastructure, only infrastructure imports from domain
📦 Applies To
PHP 7.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Domain service importing Doctrine or Guzzle directly; port interface defined in infrastructure namespace not domain; no adapter isolation from domain
Auto-detectable: ✓ Yes phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update

✓ schema.org compliant