The observer design pattern is a very common pattern in programming. The main idea behind it is creating a set of classes which will be most suitable to solve the issue of publish/subscribe kind of tasks. It is very possible that, working as a developer, you will come to a situation when one action of your code solution will need to do a couple of other actions as a consequence of that action. This pattern is a part of the group of behavioral design patterns.
Let’s try to explain this with a very simple real case scenario. Let’s imagine that you are working on a registration form for you web application. Your form data will be send to a back-end route, will need to be validated and stored to a database. After storing the user data in the database, it is very possible that the next thing you will need to do is to send a confirmation email with a link for account verification to the user email provided through the registration form right? Also, maybe you will need to notify the admin that a new user has been registered to the application. These two additional steps could be treated as separate entities and actions but will need to be subscribed to this main user registration event.
Creating the subject class
Let’s build the key Registered class that will be in charge of the post-registration process as a subject or event.
use SplObserver;
class Registered implements SplSubject
{
protected $observers = [];
public $email;
public function __construct(string $email)
{
$this->email = $email;
}
/**
* Add an observer method
*
* @param SplObserver $observer
* @return Registered
*/
public function attach(SplObserver $observer)
{
$key = spl_object_hash($observer);
$this->observers[$key] = $observer;
return $this;
}
/**
* Remove an observer
*
* @param SplObserver $observer
*/
public function detach(SplObserver $observer)
{
$key = spl_object_hash($observer);
unset($this->observers[$key]);
}
/**
* Iterate over all observers and call observer update method
*/
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
First thing we can notice in the class above is the usage of the SplSubject and SplObserver interfaces. These interfaces are from the Standard PHP Library and certainly are good starting point for building a simple observing system like this since it contains some useful contracts for creating and implementing simple observer patterns. Implementing these built in PHP interfaces, we will need to implement three mandatory methods:
- attach – needed to add new observers to the main subject
- detach – needed to detach a specific observer from the array
- notify – needed to alert all observers that an event was taking place
Creating the observers
The next step is to create the observer classes for this subject, which will need to send the user an email verification to confirm and verify their account, and notify the administrator that a new user has been registered with the system. The classes are going to look like:
use SplSubject;
use SplObserver;
class SendVerificationEmail implements SplObserver
{
public function update(SplSubject $subject)
{
// Here is the section where you will need to implement
// the email verification sending
}
}
Here is the email verification observer. The next one is the admin notification sending.
use SplSubject;
use SplObserver;
class NotifyAdmin implements SplObserver
{
public function update(SplSubject $subject)
{
// Here is the section where you will need to implement
// the admin notification sending for a new user
}
}
The observer classes are now created. As we can see from the implementations above, we are implementing the SplObserver interface from the Standard PHP Library as a built in interface that offers one single contract method, update. In our update method we can write our implementations for sending verification email and sending notification to the administrator.
Note: Just bear in mind that these classes are just for kind of logic to publish / subscribe. Implementing an email sending or notification to a recipient is safer for implementing it in different classes.
Putting it all together
Now let’s put this all together.
// Collect needed data
$email = 'newuser@test.com';
// Creating the subject
$userRegistered = new Registered($email);
// Attaching the observers
$userRegistered->attach(new SendVerificationEmail())
->attach(new NotifyAdmin());
// Notify all observers
$userRegistered->notify();
Let’s say that we have already store the user in the database previously (it is not the intent of this article) and now we have the email address of the user sending it to the Registered subject class. The next step is to attach the two observers we’ve built for this subject, SendVerificationEmail and NotifyAdmin. As you can notice, the attach method is returning an object from the same Registered class, giving us the additional possibility to chain the observers attaching as above, but this is just a personal flavour, you don’t need to do it like that.
Final words
We are done! We have successfully implement the observer design pattern using PHP. What you will need to be aware, is that this is just a simple implementation of the observer pattern. It is very common that complicated scenarios and applications will need much more complicated solutions than this with using additional data storage or maybe using separate message brokers. Just for an example, Laravel has pretty complicated implementation of the observer pattern in their Events solution. You are free to check that out if you are interested more of how they are doing it.