PHP 8: Modern PHP Development · Object-Oriented PHP 8

Interfaces, Abstract Classes and Traits

Model contracts and share behavior without deep inheritance hierarchies.

Interfaces define contracts (method signatures, constants); a class can implement many. Abstract classes share code and state while leaving some methods abstract; a class extends only one. Traits copy methods (and properties) into classes for horizontal reuse. Prefer interfaces plus composition; use abstract classes for template-method style shared behavior; use traits sparingly for small cross-cutting helpers. Since 8.2 traits can define constants, and since 8.3 class constants can be typed.

<?php
interface PaymentGateway
{
    public function charge(Money $amount, string $token): ChargeResult;
}

abstract class HttpGateway implements PaymentGateway
{
    public function __construct(protected readonly HttpClient $http) {}

    protected function post(string $url, array $body): array
    {
        return $this->http->post($url, ['json' => $body])->toArray();
    }
}

trait LogsCalls
{
    private function logCall(string $method, array $context = []): void
    {
        $this->logger->info("Calling {$method}", $context);
    }
}

final class StripeGateway extends HttpGateway
{
    use LogsCalls;

    public function __construct(HttpClient $http, private LoggerInterface $logger) { parent::__construct($http); }

    public function charge(Money $amount, string $token): ChargeResult { /* ... */ }
}

Common pitfalls

  • Deep inheritance trees that are hard to change — favor composition.
  • Traits that depend on undeclared properties of the host class (use abstract methods in the trait to require them).
  • Interfaces with too many methods; keep them small (Interface Segregation).

Key points

  • Depend on interfaces, not implementations
  • Abstract classes share code; interfaces define contracts
  • Use traits sparingly

Further reading: PHP manual: interfaces

Practice questions

When would you choose an abstract class over an interface?

Answer

When implementations share real code or state (e.g., a base HTTP gateway with helper methods). Interfaces are for contracts; you can combine both: an interface for the type, an abstract class as a convenient base.

What problem do traits solve, and what's their main risk?

Answer

They allow reusing methods across unrelated classes without inheritance. Risks: hidden coupling to host class internals, name conflicts, and code that's hard to follow when overused.

Open in the app to mark lessons complete, take notes and track your progress.