Observer Design Pattern: Real-Time Communication in Native PHP

Observer Design Pattern

The Observer design pattern in PHP is a powerful behavioral design pattern that allows objects to communicate in a one-to-many relationship. This means that when the state of one object (known as the subject) changes, all its dependent objects (known as observers) are automatically notified and updated. This mechanism is ideal for real-time notifications, decoupling systems, and making your PHP applications more maintainable and scalable.

In native PHP, implementing the Observer design pattern helps build loosely-coupled systems. This decoupling makes the code easier to test, extend, and refactor. If you’re developing event-driven systems, messaging queues, or GUI applications, the Observer pattern can help you manage complexity cleanly.

When to Use the Observer Pattern

Use the Observer design pattern in PHP when:

  • You need to notify multiple objects about a state change.
  • You want to reduce tight coupling between classes.
  • You want to implement event listeners without building a full event dispatcher system.

Real-world examples include:

  • Subscribing users to a newsletter.
  • Sending notifications to multiple services when an order is placed.
  • Updating UI elements when backend data changes.

Bad Code Example: Tight Coupling Without Observer

class OrderService {
    public function completeOrder() {
        // ...order logic...
        (new EmailNotifier())->sendEmail();
        (new Logger())->log('Order completed');
        (new AnalyticsTracker())->track();
    }
}
class EmailNotifier {
    public function sendEmail() {
        echo "Email sent.\n";
    }
}
class Logger {
    public function log($message) {
        echo "Logged: $message\n";
    }
}
class AnalyticsTracker {
    public function track() {
        echo "Analytics tracked.\n";
    }
}

What’s wrong here?

  • Tight coupling: OrderService is dependent on all the concrete services.
  • Hard to extend: Adding a new observer means modifying OrderService, violating the Open/Closed Principle.
  • Poor testability: You can’t test OrderService without triggering all other services.

Using the Observer Design Pattern in PHP

interface Observer {
    public function update(string $eventData): void;
}
interface Subject {
    public function attach(Observer $observer): void;
    public function detach(Observer $observer): void;
    public function notify(string $eventData): void;
}
class OrderService implements Subject {
    private array $observers = [];

    public function attach(Observer $observer): void {
        $this->observers[] = $observer;
    }

    public function detach(Observer $observer): void {
        $this->observers = array_filter(
            $this->observers,
            fn($obs) => $obs !== $observer
        );
    }

    public function notify(string $eventData): void {
        foreach ($this->observers as $observer) {
            $observer->update($eventData);
        }
    }

    public function completeOrder(): void {
        echo "Order completed.\n";
        $this->notify("OrderCompleted");
    }
}
class EmailNotifier implements Observer {
    public function update(string $eventData): void {
        echo "EmailNotifier: Sending email for event - $eventData\n";
    }
}
class Logger implements Observer {
    public function update(string $eventData): void {
        echo "Logger: Logging event - $eventData\n";
    }
}
class AnalyticsTracker implements Observer {
    public function update(string $eventData): void {
        echo "AnalyticsTracker: Tracking event - $eventData\n";
    }
}
// Usage
$orderService = new OrderService();
$orderService->attach(new EmailNotifier());
$orderService->attach(new Logger());
$orderService->attach(new AnalyticsTracker());

$orderService->completeOrder();

Why this is better?

  • Loose coupling: OrderService doesn’t care who is listening.
  • Scalable: New observers can be added without changing core logic.
  • Testable: Each component can be tested independently.

Benefits of the Observer Design Pattern in PHP

The Observer pattern aligns perfectly with modern development principles:

  • Open/Closed Principle: Easily extend behavior without modifying existing code.
  • Decoupling: Components operate independently, boosting reusability.
  • Dynamic relationships: Observers can subscribe or unsubscribe at runtime.

For instance, if you’re building a microservice in native PHP, using observers lets you broadcast state changes to any number of services without hardcoding dependencies.

Advanced Tip: Using SplSubject and SplObserver in PHP

PHP comes with built-in interfaces: SplSubject and SplObserver. These can simplify your implementation:

class MySubject implements SplSubject {
    private array $observers = [];
    private string $data;

    public function attach(SplObserver $observer): void {
        $this->observers[] = $observer;
    }

    public function detach(SplObserver $observer): void {
        $this->observers = array_filter(
            $this->observers,
            fn($obs) => $obs !== $observer
        );
    }

    public function notify(): void {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    public function changeData(string $data): void {
        $this->data = $data;
        $this->notify();
    }

    public function getData(): string {
        return $this->data;
    }
}
class MyObserver implements SplObserver {
    public function update(SplSubject $subject): void {
        echo "Observer received data: " . $subject->getData() . "\n";
    }
}

Final Thought

The Observer design pattern in PHP is essential for building modular and event-driven applications. By reducing class dependencies, improving scalability, and following SOLID principles, the Observer pattern ensures that your code remains flexible and robust in the face of change.

Whether you’re building simple notification systems or complex event pipelines, this pattern belongs in every native PHP developer’s toolkit.

Interested in More Design Patterns?

Discover other powerful patterns like Factory, Strategy, and Observer in this full guide:

➡️ Design Patterns in PHP – The Complete Guide to All Types