Implementing the Observer Pattern with SplObserver and SplSubject

As PHP applications grow into complex object-oriented systems, developers look to create centralized components to execute repetitive tasks. These include logging, emailing, redirects, and more. The Observer pattern is a commonly used design pattern to hook such components into an application during runtime, thereby making them reusable. Since PHP 5.1, there are two interfaces built into the Standard PHP Library (SPL) that can be implemented to use the Observer pattern in your application. They are SplSubject, and SplObserver.

As a sample implementation, we are going to create an uncaught exception handler class, aptly called ExceptionHandler. This class will implement the SplSubject interface. To implement SplSubject, three methods must be implemented: attach(), detach(), and notify(). Before showing the implementation, let’s go over what each method is supposed to do:

  • attach() – Accepts an observer that is then stored in the object
  • detach() – Removes an existing observer from the object
  • notify() – Notifies all attached observers

The notify() method definition in particular is vague, because notification depends on the context. In our case, we want to notify our observers when there in an uncaught Exception. With that explained, let’s take a look at the ExceptionHandler class:

Notice that there is an extra method defined in ExceptionHandler – the handle() method. This is the method that we are going to make the default for uncaught Exceptions (see last code snippet). Notice that this method stores the uncaught Exception as a member variable, and then calls notify. We do this so that the observers can each have access to the Exception, while maintaining the SplSubject interface!

The SplObserver should be implemented as your component – in our example, we have a Logger class and a Mailer class. SplObserver is much easier to implement; we have only one method, called update(), which takes the calling SplSubject as its only parameter. Any logging, emailing, etc. should either be executed or called from within this method. Here is a simple Logger implementation:

And also a Mailer:

Now all we have left to do is create the code and throw an Exception. The following code should go in some sort of application init() method, so it is created and set once upon the start of the request cycle:

Now, at any point during the application, any throw new Exception(‘Place your error message here’) that is uncaught will be both logged and emailed to your sysadmin. Pretty handy!

Hopefully this blog will get you started in your process of creating good modular components for your application, while using the Observer pattern to fit the components into a larger system. There are many uses for this pattern. In the next blog, I am going to outline how we can use the Observer pattern to create an event-driven component system, complete with custom event handlers. Should be a good challenge!