The Standard PHP Library
For those of you in the Boston PHP 200 Days of Coding Advanced group and for those of you who develop with design patterns, you may have noticed that I have not taken advantage of PHP’s Standard Library (SPL). In part that’s because I don’t think about it, and the other is that often I have other features for the interface I’d like to add that are not in the SPL version. Further, there are only a couple, the Iterator that Larry talks about in his book, and the Observer pattern that I’m going to discuss in this post and on April 22 at Microsoft’s NERD Center next to the MIT campus.
In an earlier post on the Observer design pattern I noted that in a future post, I’d take a look at the built-in SplObserver and SplSubject interfaces. So as promised, here it is.
The class diagram is slightly different than the original, and to indicate the built-in interfaces, the backgrounds are filled with a light tint indicating, there’s nothing for you to add. If you compare Figure 1 with the class diagram in the other Observer pattern post, you can see certain fundamental differences:

Figure 1: Observer Class diagram with SPL Interfaces
With no abstract classes as part of the interface, everything passed to the concrete Subject and Observer is going to have to be implemented. With the Subject, that means implementing the notify() method and not having some protected properties, but otherwise, there’s not a lot of differences in the structure of the SplObserver and the Observer (from scratch.)
One Message: Lots of Ways to Configure the Message
Some developers treat the Observer design pattern like a magazine subscription—one magazine; lots of subscribers. I suppose that’s a legitimate use of the Observer, but it’s very expensive. Each concrete observer must be instantiated as a unique object. While the Subject (or SplSubject) supplies the data; the observers generally create something with that data; not just look at it. So, I decided to make a simple translation simulator. A club (like any of the many PHP groups in the world) has announcements, but rather than using the Observer for sending out notifications to subscribers, I created Observers who translated the event message from English to their own language. The concrete observers are named for their languages. But to get going, play the example and download the PHP code:
When you test play the app, you’ll see that the all of the checkboxes on the left are checked and the text box is filled in with an event. Likewise, the data and day inputs are set to April and 22. You can just click the “Send Announcement” button to see the results. If you change the event to something other than “200 Days of Code” the only change you’ll see is in the English version. The other ones are only a simulation of a translation except for the month—they are actually translated. The idea would be to use a translation Web service to do the actual translations.
Beginning with the implementation of the SplSubject (ClubEvents), you can see the three abstract methods have been implemented using the signature from the SplMethod interface. (Their abstract form is shown at the top as comments.)
class ClubEvents implements SplSubject
{
/*Built-in abstract methods
*abstract public void attach ( SplObserver $observer )
*abstract public void detach ( SplObserver $observer )
*abstract public void notify ( void )
*/
private $member;
private $observerSet = array();
private $content= array();
//add observer
public function attach(SplObserver $observer)
{
array_push($this->observerSet, $observer);
}
//remove observer
public function detach(SplObserver $observer)
{
foreach($this->observerSet as $keyNow => $valNow)
{
if ($valNow == $observer)
{
unset($this->observerSet[$keyNow]);
}
}
}
//Set event name, month and day
public function setState(array $content)
{
$this->content = $content;
$this->notify();
}
public function getState()
{
return $this->content;
}
//Notify "subscribers"
public function notify()
{
foreach ($this->observerSet as $value)
{
$value->update($this);
}
}
}
?>
|
If you’re familiar with the first example of the Observer on this blog, you’ll see similarities in the concrete Subject. About the only significant difference is the fact that the notify() method is wholly implemented in the concrete class (ClubEvents) instead of the Subject abstract class. The information (or data) generated by the SplSubject comes from the Client and triggers the notify() methods by calling setState() method. So instead of looking at the Observers next, we’ll look at the Client.
The Client’s Unlikely Role
Note: A primary principle of design patterns is,
Program to the interfaces; not the implementations.
In discussing the single SplSubject implementation (ClubEvents) and the many SplObserver implementations, I’ll be referring to them by the interface name except in certain specific cases. However, the references are to any implementation of either since we must assume (correctly) that any implementation contains a certain set of methods established in the abstract parent classes built into the Standard PHP Library (SPL).
The Client is not depicted in the Observer class diagram, but it can play a key role in the Observer pattern, especially in PHP which is not exactly an event-driven language. So if events are not going to be making the changes in the concrete Subject, it’s pretty much up to the Client. The Gang of Four note,
Make clients responsible for calling Notify [notify()]…
In this simple example, the change event is triggered by the Client calling SplSubject->setState().
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
// Autoload given function name.
function includeAll($className)
{
include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
/*Begin Class */
class Client
{
private $subs=array();
private $skip=array();
private $content=array();
private $clubEvent;
private $event;
private $dmonth;
private $dday;
public function request()
{
$this->setProps();
$this->clubEvent=new ClubEvents();
array_push($this->content,$this->event);
array_push($this->content,$this->dmonth);
array_push($this->content,$this->dday);
if(count($this->subs))
{
foreach($this->subs as $value)
{
$this->clubEvent->attach(new $value);
}
}
if(count($this->skip))
{
foreach($this->skip as $value)
{
$this->clubEvent->detach(new $value);
}
}
$this->clubEvent->setState($this->content);
}
private function setProps()
{
if(isset($_POST['advise']))
{
$this->subs =$_POST['advise'];
}
if(isset($_POST['remove']))
{
$this->skip=$_POST['remove'];
}
$this->event=$_POST['clubEvent'];
$this->dmonth=$_POST['month'];
$this->dday=$_POST['day'];
}
}
$worker= new Client();
$worker->request();
?>
|
The Client class is composed of two methods: 1) request() and 2) setProps(). The setProps() method sets the values of all of the properties pulled in through the superglobals. Two of the superglobals hold arrays, advise[] and remove[]. The arrays contain the names of the observers that “subscribe” to the SplSubject and these data are used to provide the SplSubject with raw information it uses to dispense among the SplObservers. This is done by the request() method that pushes the contents of the properties into an array named $content. Once it’s all ready, request() sets the SplSubject’s state ($clubEvent->setState($content), which then notifies all of the subscribed SplObservers that there’s been an update.
The Observers Get to Work
In some implementations of the Observer pattern it’s the Observers who do most of the work even though the Subject seems to be center because it changes state and sends the information to the Observers. However, it’s the Observers who do something with the information—they don’t just “read the mail” from the Subject. In the first Observer design pattern posted on this blog, the Observers formatted the Subject information into a bar chart and a table. In the SplObserver implementation, the observers “translate” the data into different languages. Figure 2 shows a file diagram of the classes and their relationship to the SplSubject and SplObserver as well as one another and the helper class, Poster.

Figure 2: File Diagram of SplObserver Pattern
Each of the files with the names of different languages represents an observer that take the information from the subject and translates it into its own language. However, the only content that is really translated are the months of the year. The idea is that each observer would call a translation Web service as was shown in an earlier post using a geolocation Web service. (You can implement that on your own if you wish.) The French SplObserver implementation shows the pattern that all of the other non-English observers implement:
class French implements SplObserver
{
private $event;
private $dmonth;
private $dday;
private $current=array();
private $package;
public function update(SplSubject $subject)
{
$language ="French";
$this->current=$subject->getState();
$this->translate();
$bPHP="Presents de PHP de Boston";
$this->package="
|
Like all of the other languages, this implementation has none of the special accents and other characters used because they showed up as question marks (?) on my screen. Please forgive me for that because I know they’re important and can change the meaning of words. Please feel free to make the necessary changes on your own system to correct them if you would like.
The SplObserver implementations have two methods: update() [required by the interface] and translate(). The update() method pulls in an instance of the SplSubject and from it gets its current state and puts it into an array, $current. The translate() method takes the English from the first two elements of the $current array and translates them to the months of the year or a single “200 days of code” and stores them in appropriate private variables.
Finally, the output is handled by a helper class, Poster. A string named $package with some HTML formatting is then fully formatted in Poster and output to the iframe window in the HTML document. That’s all there is to it.
The HTML UI
The Announcement.html UI has five pieces of data:
- The Month (in a select input element)
- The Day (in a number input)
- The Club Event (in a text input)
- The Subscribers (in an array of checkboxes)
- The Un-subscribers (in an array of checkboxes)
These are all passed to the Client class. Each of the values (January, February, etc) in the select form are the names of the SplObserver implementations. This allows the Client to implement the class and attach it to the SplSubject simply using the value of the array element for the class name (e.g., new $value where $value is the name of a class in the array.)
More and more I’ve found the value of thinking of the HTML document as a place to set up my classes in a design pattern. Both scalar and compound variables may serve as class name resources, and it saves from having to use conditional statements in the Client to sort out which class to call.
![]() |
The two HTML5 arrays are advise[] and remove[]. When passed to the Client as superglobals, only those that have been checked are included in the array; so, there’s no need to query the array in the Client as to whether a checkbox has been clicked or not. The moral to this story is:
Begin planning your design pattern classes and methods in the HTML document.
It saves time, keeps the code neater and is easier to make changes and updates.
What about Italian, Chinese, Russian, Ukrainian and Zulu?
Some readers may wonder,
Why wasn’t my language included?.
Besides the fact that I tend to mangle all languages, the world has so many languages that I just started with a few. But let’s face it, a whole lot of people speak Japanese, Russian, Chinese, Bahasa Indonesia and Arabic; so let’s see how easy it is to add your language. We’ll start with Zulu since it’s at the end of the alphabet and gets left out way too often. Just take any one of the SplObserver implementations “save-as” Zulu.php and make the following changes in the code:
class Zulu implements SplObserver
{
private $event;
private $dmonth;
private $dday;
private $current=array();
private $package;
public function update(SplSubject $subject)
{
$language ="Zulu";
$this->current=$subject->getState();
$this->translate();
$bPHP="PHP Boston Izipho:";
$this->package="
|
Then, in the HTML document, add the following lines:
/*Right beneath: English |
That’s all there is to it. The value of OOP and design patterns is the ability to easily add and change components. This means that you can re-use code and make changes in even the most complex of programs, and everything keeps working together well. I included the Zulu.php file and the AnnouncerZ.html in the download files, and you can see how the Zulu language was added. Now add your own language if it’s not on the list (or badly mangled).
Copyright © 2015 William Sanders. All Rights Reserved.
0 Responses to “PHP Observer Design Pattern: The SplObserver”