Menu
Coddy logo textTech

Observer Pattern

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 73 of 91.

The Observer Pattern is a behavioral design pattern that establishes a one-to-many relationship between objects. When one object (the subject) changes state, all its dependents (the observers) are automatically notified and updated.

Think of a newsletter subscription. The newsletter is the subject, and subscribers are observers. When a new edition is published, all subscribers receive it automatically without the newsletter needing to know the details of each subscriber.

Here's a basic implementation in PHP:

<?php
interface Observer {
    public function update(string $message): void;
}

class Newsletter {
    private array $subscribers = [];
    
    public function subscribe(Observer $observer): void {
        $this->subscribers[] = $observer;
    }
    
    public function publish(string $content): void {
        foreach ($this->subscribers as $subscriber) {
            $subscriber->update($content);
        }
    }
}

class EmailSubscriber implements Observer {
    public function __construct(private string $email) {}
    
    public function update(string $message): void {
        echo "Sending to {$this->email}: $message\n";
    }
}

$newsletter = new Newsletter();
$newsletter->subscribe(new EmailSubscriber("alice@example.com"));
$newsletter->subscribe(new EmailSubscriber("bob@example.com"));
$newsletter->publish("New article released!");

Output:

Sending to alice@example.com: New article released!
Sending to bob@example.com: New article released!

The pattern decouples the subject from its observers. The Newsletter class doesn't need to know whether it's notifying email subscribers, SMS subscribers, or push notification services. It simply calls update() on anything that implements the Observer interface. This makes adding new observer types effortless without modifying existing code.

challenge icon

Challenge

Easy

Let's build a stock price alert system using the Observer Pattern. When a stock's price changes, all registered investors should be notified automatically — a perfect real-world application of this pattern.

You'll organize your code across four files:

  • Observer.php — Define an Observer interface with a single method update(string $stockName, float $price): void. This is the contract that all observers must follow to receive notifications.
  • Investors.php — Include the Observer file and create two classes that implement the interface:
    • EmailInvestor — Takes an email address in its constructor (use constructor promotion). Its update() method prints "Email to [email]: [stockName] is now $[price]"
    • SmsInvestor — Takes a phone number in its constructor. Its update() method prints "SMS to [phone]: [stockName] is now $[price]"
  • Stock.php — Include the Observer file and create a Stock class that acts as the subject. Your stock should:
    • Store the stock name and current price (use constructor promotion for the name, initialize price to 0.0)
    • Maintain a private array of observers
    • Have a subscribe(Observer $observer): void method to add observers
    • Have a setPrice(float $price): void method that updates the price and notifies all observers
    When notifying observers, call each observer's update() method with the stock name and new price.
  • main.php — Include the Investors and Stock files. You'll receive three inputs: a stock name, an email address, and a phone number.

    Create a Stock with the given name. Subscribe an EmailInvestor with the email address and an SmsInvestor with the phone number.

    Set the stock price to 150.50 to trigger notifications to all subscribers.

The Observer Pattern keeps your Stock class decoupled from the specific notification methods. You could easily add a PushInvestor or SlackInvestor later without modifying the Stock class at all.

Cheat sheet

The Observer Pattern establishes a one-to-many relationship where a subject automatically notifies all observers when its state changes.

Key Components:

  • Observer Interface — Defines the contract for observers with an update() method
  • Subject — Maintains a list of observers and notifies them of state changes
  • Concrete Observers — Implement the Observer interface to receive notifications

Basic Implementation:

<?php
interface Observer {
    public function update(string $message): void;
}

class Subject {
    private array $observers = [];
    
    public function subscribe(Observer $observer): void {
        $this->observers[] = $observer;
    }
    
    public function notify(string $data): void {
        foreach ($this->observers as $observer) {
            $observer->update($data);
        }
    }
}

class ConcreteObserver implements Observer {
    public function __construct(private string $name) {}
    
    public function update(string $message): void {
        echo "Notifying {$this->name}: $message\n";
    }
}

$subject = new Subject();
$subject->subscribe(new ConcreteObserver("Observer1"));
$subject->subscribe(new ConcreteObserver("Observer2"));
$subject->notify("State changed!");

Benefits:

  • Decouples the subject from its observers
  • Easy to add new observer types without modifying existing code
  • Supports dynamic subscription/unsubscription

Try it yourself

<?php
require_once 'Investors.php';
require_once 'Stock.php';

// Read inputs
$stockName = trim(fgets(STDIN));
$email = trim(fgets(STDIN));
$phone = trim(fgets(STDIN));

// TODO: Create a Stock with the given name

// TODO: Subscribe an EmailInvestor with the email address

// TODO: Subscribe an SmsInvestor with the phone number

// TODO: Set the stock price to 150.50 to trigger notifications
?>
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming