Observer in PHP [Design pattern with examples]
Coding (Php 7.x)
Do you want to notify users of your application, or launch products of your web store successfully? here is the way to do it!
The Observer is a software design pattern that belongs to the category of behavioural patterns, and it helps one object (called the subject) of an application communicating a change of state to other object observing the subject.
One of the goals of any web developer is to create an application that can have changes to one element and do not affect any of the other code,
This principle is commonly called Orthogonality.
Unfortunately, orthogonality is often impossible to achieve and this is the reason we must use automated tests in our code and run our testing before committing new features to the production environments.
There are several ways to minimize the ripple effect that an update can cause on a web application.
Design patterns and behavioural patterns in this specific case is one of them.
The Series
If you have followed my blog you might already know that I am creating a series about Design Pattern.
In this series, I describe the most popular design patterns available for PHP developer and not.
I am using very easy examples to explain elaborate concepts and I do so using PHP language and clear UML schemes
You can discover the other design pattern following the links below:
Behavioral patterns
In this article instead, we are going to discover a behavioral pattern,
We use behavioral patterns, to manage how the different objects in a web application need to behave with each other.
How to guide the various requests, manage composition relationship and how to update elements that depend on other objects to perform their tasks.
Here is a deeper explanation of Behavioral patterns by Sameeha Rahman.
The observer
The observer pattern is composite by at least 2 different objects.
A lot of time more than that, but it is fine because this system is very reliable.
The object just mentioned are the observable (also subject) and the observer.
The subject is the core element of the system
It usually keeps a state that under certain condition may vary and activate the pattern.
The other part of this schema is the observer or observers.
These are the elements that perform the actual action, as the name suggests they look at the subject and wait for some changes to be activated.
The procedure is quite easy to understand.
You can image a request as a pull or a push one.
In some case, you need to extrapolate some data or information from somewhere by actually request it from the original source.
In some other case, for instance, when the objects are multiple or there are several instances of observers it is better to leave the system static and act only if requested.
The latter represents what’s happening during a “push request”,
Imagine calling the train station every day before and after going to work to make sure there will be trains available for your commute.
That would be quite annoying, just think of how many commuters the call centre would be dealing with daily.
A much better way to arrange this is to provide your email on the transportation system and get notified only when a problem occurs.
In this way, the performance is way better because instead of having thousands of daily requests pulling (asking) for information the system push (send) information only when needed.
This is a very simple pattern, to make it work properly we only need to be sure that the observable object has the list of all the observers and that the observer can perform an action when needed.
Breaking the definition down
The observer pattern defines a one to many relationships between objects so that one object changes state all of its dependencies are notified and updated automatically
The observer pattern defines a one to many relationships ...
A one to many relationships is when an element of the application is related to one or more other elements.
Patrick Kennedy, made a post on his blog in which he explains the different type of relationship.
For instance, in a family, there may be one or several children but the father and the mather are only one.
As explained in the previous paragraphers we have one subject that is related to one or more other objects of the application, them being the observers. And this is one of the advantages of having a single element pushing notifications to several others rather than have lot’s of childer asking for updates continuously.
… so that one object changes state ...
Pretty straightforward here, the one object is the subject, the only one that has a state relevant on our applications
… all of its dependencies are notified and updated automatically.
If the observers are “subscribed” on the subject’s list they can get notified every time there is an update in the state of the subject.
Looking at the UML
Starting implementing the contract we have the interface of the subject, the observable class, this has to be an interface, thus we usually prefix it with I_ (there are several ways to indicate and interface you can choose the one you prefer).
This interface has 3 methods that basically manage the list of observers attached.
The first method add observers to the list,
the second method removes the observers to the list the
third methods in the one that start the action of the observers in our UML we call it notifyObservers()
If you haven seen UML before here is the link
The related objects have to follow a contract as well, an interface that specifies the command the observers need to perform.
The relationship between those two interfaces in one-to-many, an I_Observeable is related with one or more I_Observer,
The way the system works is that the Observable call the updateObserver() method of the observers included in the list at a given time.
Every Observer has personalized tasks to perform once the updateObserver() method is triggered.
Surely,
these interfaces cannot do anything on their own,
We need concrete classes.
Consider that we have at least one class for each interface,
Since these are concrete classes that extend the interfaces they need to include the methods within the interface.
In our case, we need the Observable and the Observer class.
Of course,
each class can also have other methods independently.
Remember we can have one or multiple observers
Some methods that the Observable class might have are the getter and setter for the state, the parameter that will trigger the start of the communication between these parts.
What problem we are trying to solve
So far we have seen what the pattern is about and how to implement it via the UML schema.
Let’s understand for a second why someone came up with this system rather than just using relationships between concrete classes.
The final goal of design patterns is to create a long-lasting solution.
This way to create application may seem more complicated, especially if this is the first time you approach design patterns.
The reason these patterns are so used and useful is that once understood and correctly implemented you should not be worried about breaking pieces of your application for a long time.
How to implement it
In the previous paragraphs, we saw an abstract UML scheme of the Observer design pattern,
Now it is time to implement it in a real-world example.
In the tutorial in this chapter, we are pretending to be working on an online store / eCommerce we are not going to take care of the ordering system, or menu management but our focus will be on the marketing.
Our client, the owner of this store has already several products and a pr/marketing team that manage mailing, social account, affiliate links and their own in-house database.
What the client asked us is to create a system that notifies all the users registered in these accounts when a product goes on sale or under special prices.
To begin with,
let’s analyze the task:
We have one or more products and several ways to market it,
These different ways are already in place and they "wait" for the products to go on sale to perform the action of telling the customers about the offer.
The products have a state which can be an onSale boolean or a discount field as float or double.
It sounds like the observer pattern fits perfectly in the development of this task.
Create the classes
As a first thing, we need to create the store the core of the business and the main object of the system
The marketing and PR departments of the business have set different avenues up to connect with the customers and create a long-term relationship
Each avenue is in charge of sending messages to the user.
This is a similar task among the different ways, which means that they can be represented by a unique interface
To make the system scalable we now need to define the role of our objects,
the store is the object that needs to be observed
Thus update the store:
Then we need to create the observers.
We already have the observer interface in our applications with all the avenues but they do not have a common observer interface that connects them.
Let’s add it to our system
Since Each avenue is now also represented as an individual observer we need to add the updateObserver method to it.
Analyzing the UML that we have we can see that the system is not really that complicated.
If we were to build an actual store we might have thought to add the product as observable rather than the store but since article tutorial just focuses on the pattern I believe it is much easier to understand this way.
Another part of the UML that you need to take care of is the concrete avenues they are bought concrete instances of observers and concrete avenues.
You are going to see as we implement both interfaces in the class.
Now that the UML is ready, let’s write some code:
$store = new Store ; // set the store up
The store has been created.
It can set and get the items discounted.
plus, since it implements the I_Observeable interface it has all the method that enables it to add remove and notify observers.
We now need to create the avenue and the observer interface
Nothing difficult here, they are just normal interface
If you have difficulties read Basics of PHP
The remaining part of our application is the creation of unique avenues.
below we have an example of the MailPlatform class
Class MailPlatform implements I_Avenue, I_Observer { Public function updateObserver() { … } Public function sendMessage() {... } }
This is the same for all the concrete avenues.
How do we use them?
$mailchimp = new MailPlatform; $store->addObserver(mailchimp); $facebook = new FacebookPage; $store->addObserver(facebook); // mailchimp and facebook now will get notified is something changes
We have added the facebook page and the Mailchimp platform to the list of observers, it can be a complex operation or a simple array the important is that the observer class has been added to the list of observer and that it has a relationship with the I_observer interface
public function notifyObservers() { foreach (I_Observer as $observer) { $observer->updateObserver() } } $store->notifyObservers(); // mailchimp and facebook notified
within the Store class, we have the notifyObservers() method that loop through the list of observer included so far and invoke the updateObserver method of each observer.
Note that each observer does perform a different task such as sending an email, publish a video on Youtube, post an article on the blog or post a link on social media.
$store->removeObserver(FacebookPage); // facebook not an observer anymore
This command is quite clear.
once we do not need anymore we can remove an observer from our list.
This way we can keep notifying avenues but we can keep under control which will perform actions
$store->notifyObservers(); // only mailchimp notified
if we run the command again only the Mailchimp avenue will be triggered this time.
Lesson learned from this solution
This is one of the best solutions we have when needing a system that notifies class in our web application.
The observer pattern can be used in online stores like the one above but it is also the preferred choice for news feed and social network, (this is how the notification bell work on Facebook, Twitter and Youtube).
Another place where you will be likely using this design pattern is when developing chats,
The various chatroom will be the observable objects and the observers are the user enrolled to the chatroom.
Now that you understood the purpose of this pattern you can use in the cases you think it will fit the most.
Where you can go now?
This is the third episodes of this series if you haven't seen the previous one I suggest you can start from the beginning by reading how to use the factory method pattern.
Otherwise, you might prefer to look into upgrading to PHP 7.4 with the most detailed guide available online at the moment.