Laravel 12 Contracts Explained Simply: A Practical Guide What Are Laravel Contracts?
Imagine you're building a house. Contracts are like the blueprints that define how different parts (like doors, windows, or electrical systems) should work, without specifying exactly which brand or model to use. In Laravel, contracts are interfaces that define how core services should behave.
Key Points:
- Contracts are interfaces (not classes)
- They define what services should do, not how
- Laravel provides implementations for all contracts
- You can swap implementations if needed
Contracts vs. Facades: What's the Difference?
Think of facades as shortcuts and contracts as formal agreements:
| Feature | Facades | Contracts |
|---|---|---|
| Usage | Simple static calls | Type-hinted dependencies |
| Flexibility | Less flexible | More flexible |
| Testability | Good | Excellent |
| Explicit Dependencies | No | Yes |
Example: Sending an email
// Using Facade
Mail::to('user@example.com')->send(new WelcomeEmail());
// Using Contract
public function __construct(
protected Illuminate\Contracts\Mail\Mailer $mailer
) {}
public function sendWelcomeEmail()
{
$this->mailer->to('user@example.com')->send(new WelcomeEmail());
}
Why Use Contracts?
- Clear Dependencies: Your class explicitly declares what it needs
- Flexibility: Easily swap implementations (great for testing)
- Decoupling: Your code depends on interfaces, not concrete classes
- Framework Agnostic: Useful for packages that work across frameworks
Practical Examples
Example 1: Using Cache Contract
use Illuminate\Contracts\Cache\Repository as Cache;
class UserRepository
{
public function __construct(
protected Cache $cache,
protected User $model
) {}
public function getActiveUsers()
{
return $this->cache->remember('active_users', 3600, function() {
return $this->model->where('active', true)->get();
});
}
}
Example 2: Queue Contract for Background Jobs
use Illuminate\Contracts\Queue\Queue;
class ReportGenerator
{
public function __construct(
protected Queue $queue
) {}
public function generateAsync(Report $report)
{
$this->queue->push(new GenerateReportJob($report));
}
}
Example 3: Filesystem Contract for Cloud Storage
use Illuminate\Contracts\Filesystem\Filesystem;
class DocumentUploader
{
public function __construct(
protected Filesystem $storage
) {}
public function upload(User $user, UploadedFile $file)
{
$path = "documents/{$user->id}/".$file->hashName();
$this->storage->put($path, file_get_contents($file));
return $path;
}
}
When to Use Contracts vs Facades
Use Contracts When:
- Writing package code that might work with other frameworks
- You want to be explicit about dependencies
- You need maximum testability
- You might need to swap implementations
Use Facades When:
- Building quick application code
- Prototyping or in simple controllers
- The convenience outweighs the need for explicit dependencies
Testing with Contracts
Contracts make testing much easier. Here's an example with the Mail contract:
// In your service
public function __construct(
protected Illuminate\Contracts\Mail\Mailer $mailer
) {}
public function notifyUser(User $user)
{
$this->mailer->to($user->email)->send(new NotificationMail());
}
// In your test
public function test_notification_sent()
{
$mailer = Mockery::mock(Illuminate\Contracts\Mail\Mailer::class);
$mailer->shouldReceive('send')->once();
$service = new MyService($mailer);
$service->notifyUser(new User(['email' => 'test@example.com']));
}
Common Contracts and Their Uses
Here are some frequently used contracts:
Cache (
Illuminate\Contracts\Cache\Repository)- Store and retrieve cached data
- Example:
$this->cache->get('key')
Queue (
Illuminate\Contracts\Queue\Queue)- Dispatch background jobs
- Example:
$this->queue->push(new Job())
Filesystem (
Illuminate\Contracts\Filesystem\Filesystem)- Work with files (local or cloud)
- Example:
$this->filesystem->put('file.txt', 'content')
Mail (
Illuminate\Contracts\Mail\Mailer)- Send emails
- Example:
$this->mailer->send(new Mailable())
Events (
Illuminate\Contracts\Events\Dispatcher)- Dispatch and listen to events
- Example:
$this->events->dispatch(new OrderShipped($order))
How Laravel Resolves Contracts
When you type-hint a contract in a constructor, Laravel automatically resolves the appropriate implementation:
// Laravel will inject the default cache implementation
public function __construct(
Illuminate\Contracts\Cache\Repository $cache
) {
$this->cache = $cache;
}
This works because Laravel's service container knows which concrete class to use for each interface.
Creating Your Own Contracts
You can create contracts for your own services:
namespace App\Contracts;
interface PaymentProcessor
{
public function charge(float $amount, array $options);
public function refund(string $transactionId);
}
// Implementation
class StripePaymentProcessor implements PaymentProcessor
{
public function charge(float $amount, array $options) { /* ... */ }
public function refund(string $transactionId) { /* ... */ }
}
// Usage
public function __construct(
protected App\Contracts\PaymentProcessor $payment
) {}
Best Practices
- Prefer contracts in long-lived code - They make your code more maintainable
- Use facades for simple apps - When you don't need the flexibility
- Be consistent - Don't mix contracts and facades randomly in the same project
- Document dependencies - Contracts make dependencies obvious
- Use for critical services - Especially those that might need swapping
Performance Considerations
You might wonder - do contracts impact performance? The answer is:
- Negligible difference in production
- Slightly more setup in development
- The benefits for maintainability usually outweigh any tiny performance cost
Conclusion
Laravel Contracts are powerful tools that:
- Make your dependencies clear
- Improve testability
- Allow flexible implementations
- Help create better architecture
While facades are great for quick development, contracts provide the structure and flexibility needed for larger, more complex applications. By understanding both, you can choose the right tool for each situation in your Laravel projects.
Projects to explore next
Source-code projects from the KritiMyantra catalogue. Check each project's details before buying.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure & Mi...
Flask Blog CMS with Admin Dashboard — Python Source Code
A Flask-based blogging website with a built-in admin dashboard. Manage articles, images, categories, tags and featured p...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes preconfigu...
Comments
No comments yet. Be the first to comment.
Sign in to join the discussion.