0

Contract — an interface used as a formal guarantee between caller and implementor

Beginner5 min read·eng-12-004
interviewpsrsolid

Definition

A contract, in OOP and specifically in Laravel's vocabulary, is an interface used as a formal, enforceable guarantee between the code that provides a capability and the code that consumes it. The interface specifies what methods exist, what parameters they accept, and what they return — nothing more. Any class claiming to fulfill the contract must implement every method in exactly that signature. The word "contract" emphasizes the legal-grade commitment: the caller can depend on the contract without knowing or caring which class is behind it.

In Practice

php
<?php

// The contract: a formal specification of what a mailer can do
namespace App\Contracts;

interface Mailer
{
    public function send(string $to, string $subject, string $body): bool;
    public function queue(string $to, string $subject, string $body): void;
}

// One implementation of the contract
namespace App\Mail;

use App\Contracts\Mailer;

class SmtpMailer implements Mailer
{
    public function send(string $to, string $subject, string $body): bool
    {
        // SMTP logic here
        return true;
    }

    public function queue(string $to, string $subject, string $body): void
    {
        // Queue logic here
    }
}

// Another implementation — same contract, different mechanism
class NullMailer implements Mailer
{
    public function send(string $to, string $subject, string $body): bool
    {
        return true; // no-op for testing
    }

    public function queue(string $to, string $subject, string $body): void
    {
        // do nothing
    }
}

// Consumer depends on the contract, not the concrete class
class OrderService
{
    public function __construct(private Mailer $mailer) {}

    public function placeOrder(Order $order): void
    {
        // ...
        $this->mailer->send($order->email, 'Confirmation', 'Your order is placed.');
    }
}

// In a service provider: swap implementations without touching OrderService
app()->bind(Mailer::class, SmtpMailer::class);         // production
app()->bind(Mailer::class, NullMailer::class);          // tests

Laravel ships with a suite of contracts in Illuminate\Contracts\*Cache\Repository, Auth\Guard, Queue\Queue, Mail\Mailer, and many more. These are the interfaces that decouple application code from framework implementations. You can swap illuminate/queue for a different queue driver without touching any class that depends on Illuminate\Contracts\Queue\Queue.

In Context

In interviews, "contract" is often used in the context of dependency inversion. The question is usually "how do you make code testable?" or "how do you swap implementations?" — both answers run through the concept of programming to a contract (interface) rather than a concrete class. If you can say "I bind the contract in the service provider and inject the interface in the constructor," you have demonstrated the full picture.

A common misconception is that "contract" and "interface" are identical terms. They are not — every contract is an interface, but not every interface functions as a contract. An interface used only internally, never swapped or tested against a mock, is not functioning as a contract in the architectural sense. The word "contract" implies the intent: consumers will rely on this specification across module or team boundaries.

Related terms: "interface" is the PHP language construct; "contract" is the architectural intent. "Abstract class" can serve a similar role but forces an inheritance relationship; an interface-as-contract enables composition. In Laravel specifically, "facades" are syntactic sugar that resolve the underlying contract from the container.