PHP SplObserver and SplSubject Tutorial
This article explains how to implement the Observer design pattern in
PHP using the built-in SplObserver and
SplSubject interfaces. You will learn the purpose of these
interfaces, how they facilitate decoupled communication between objects,
and how to implement them in your PHP applications with a practical code
example.
Understanding the Observer Pattern in PHP
The Observer pattern is a software design pattern where an object (known as the Subject) maintains a list of its dependents (known as Observers) and notifies them automatically of any state changes.
Instead of writing custom interfaces to implement this pattern, PHP
provides the Standard PHP Library (SPL) which includes two built-in
interfaces: SplSubject and SplObserver. These
interfaces standardize how objects communicate state changes in PHP.
The SplSubject Interface
The SplSubject interface represents the object that is
being observed. It is responsible for managing its observers and
notifying them when its state changes. To implement
SplSubject, a class must define three methods:
attach(SplObserver $observer): Registers an observer to the subject’s internal list of subscribers.detach(SplObserver $observer): Removes an observer from the subject’s subscriber list.notify(): Loops through all registered observers and calls theirupdate()method.
The SplObserver Interface
The SplObserver interface represents the object that
wants to be notified when the subject changes state. To implement
SplObserver, a class must define a single method:
update(SplSubject $subject): This method is automatically triggered when the subject calls itsnotify()method. It receives the subject instance as an argument, allowing the observer to read the subject’s updated state.
Practical Code Implementation
Here is a practical example of a user registration system where a
UserRegistry (Subject) notifies an
EmailNotifier and a Logger (Observers) when a
new user signs up.
<?php
// 1. Implement the Subject
class UserRegistry implements SplSubject {
private array $observers = [];
private string $username;
// Standard attach method
public function attach(SplObserver $observer): void {
$oid = spl_object_hash($observer);
$this->observers[$oid] = $observer;
}
// Standard detach method
public function detach(SplObserver $observer): void {
$oid = spl_object_hash($observer);
unset($this->observers[$oid]);
}
// Notify all attached observers
public function notify(): void {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
// Application logic that triggers notification
public function registerUser(string $username): void {
$this->username = $username;
echo "UserRegistry: Registering user '{$username}'.\n";
$this->notify();
}
// Getter to allow observers to read state
public function getUsername(): string {
return $this->username;
}
}
// 2. Implement the Observers
class EmailNotifier implements SplObserver {
public function update(SplSubject $subject): void {
if ($subject instanceof UserRegistry) {
echo "EmailNotifier: Sending welcome email to " . $subject->getUsername() . ".\n";
}
}
}
class Logger implements SplObserver {
public function update(SplSubject $subject): void {
if ($subject instanceof UserRegistry) {
echo "Logger: User " . $subject->getUsername() . " has been logged to database.\n";
}
}
}
// 3. Execution
$userRegistry = new UserRegistry();
$emailNotifier = new EmailNotifier();
$logger = new Logger();
// Attach observers to the subject
$userRegistry->attach($emailNotifier);
$userRegistry->attach($logger);
// Trigger a state change
$userRegistry->registerUser("JohnDoe");Output:
UserRegistry: Registering user 'JohnDoe'.
EmailNotifier: Sending welcome email to JohnDoe.
Logger: User JohnDoe has been logged to database.
Key Benefits of Using SPL Interfaces
- Loose Coupling: The
UserRegistrydoes not need to know the specific implementation details of theEmailNotifierorLogger. It only knows that they implement theSplObserverinterface. - Standardization: By using built-in PHP interfaces, your code becomes more readable and standard for other PHP developers who are already familiar with the SPL library.
- Dynamic Relationships: Observers can be attached or detached at runtime, allowing you to easily configure your application behavior dynamically.