PHP and Object-Oriented Programming
OOP Concepts in Laravel
Interfaces, traits, abstract classes, and dependency injection
OOP in Practice, Not Theory
You don't need a computer science degree to build great Laravel apps. But you do need to understand the OOP concepts that Laravel is built on — because they show up in every controller, model, and service you write.
Interfaces: Contracts
An interface defines a contract — a set of methods that a class must implement, without specifying how:
interface PaymentGateway
{
public function charge(int $amount, string $currency): PaymentResult;
public function refund(string $transactionId): bool;
}
Any class that implements this interface MUST have both methods. This lets you swap implementations without changing the code that uses them:
class StripeGateway implements PaymentGateway { /* ... */ }
class PayPalGateway implements PaymentGateway { /* ... */ }
Laravel uses interfaces extensively — they're called Contracts in the Illuminate\Contracts namespace. When you type-hint Cache or Queue, you're often using an interface.
Abstract Classes: Partial Implementations
An abstract class is a class that can't be instantiated directly. It provides some implemented methods and requires subclasses to implement others:
abstract class Notification
{
abstract public function via(): array;
abstract public function toMail(): MailMessage;
// Concrete method available to all subclasses
public function shouldSend(): bool
{
return true;
}
}
The difference from interfaces: abstract classes can have actual code (shared behavior), while interfaces only define method signatures.
Traits: Reusable Behavior
Traits let you share methods across classes without inheritance. PHP doesn't support multiple inheritance, so traits fill the gap:
trait HasSlug
{
public function getRouteKeyName(): string
{
return 'slug';
}
public static function findBySlug(string $slug): ?static
{
return static::where('slug', $slug)->first();
}
}
Laravel is full of traits: SoftDeletes, HasFactory, Notifiable, HasApiTokens. You use them by adding use TraitName; inside a class.
Dependency Injection
Dependency injection means passing objects a class needs rather than having it create them internally:
// Without DI — tightly coupled
class OrderService
{
public function process()
{
$gateway = new StripeGateway(); // Hard-coded dependency
}
}
// With DI — loosely coupled
class OrderService
{
public function __construct(private PaymentGateway $gateway) {}
public function process()
{
$this->gateway->charge(...); // Uses whatever was injected
}
}
Laravel's service container handles the injection automatically. When you type-hint a class in a controller constructor or method, the container resolves it for you. This is why you never see new inside controllers — the container builds everything.
Key Takeaways
- Interfaces define contracts. They enable swappable implementations and are core to Laravel's architecture.
- Abstract classes provide partial implementations — shared behavior plus required methods.
- Traits share methods across unrelated classes. Laravel uses them extensively (
SoftDeletes,HasFactory, etc.). - Dependency injection keeps classes loosely coupled. Laravel's container does this automatically when you type-hint.
Ask me anything about this lesson.
I have the full lesson content as context.