Introducing the Flyweight Pattern with PHP 5

Among the considerable variety of structural design patterns that can be implemented with PHP 4 (and PHP 5, by the way), there’s one in particular that deserves special attention. It’s easy to apply in the context of a given web application, and it offers remarkable functionality when it comes to preventing the unnecessary instantiation of different classes. This two-part series covers that pattern.

Naturally, if you already read the title of this series, then you’ll know that I’m speaking specifically of the flyweight pattern. But before I go into further explanations, let me tell you briefly how this pattern works. This will give you a better idea of how and when it can be used.

In simple terms, when the flyweight pattern is applied, it’s possible to specify programmatically that a particular class is going to have only a predefined number of instances, which are shared within the same implementation. This simple concept itself introduces an immediate benefit: it prevents unnecessary instantiations of the class in question across the same application, which results in a noticeable improvement in the performance of certain systems that must work with heavy loads.

Certainly, if you reread the above definition, it’s clear to see that a flyweight class can be considered a straightforward approach to keep the creation of objects carefully balanced. This can improve the web server’s overall performance, as I mentioned a few lines above.

Nonetheless, this series isn’t limited to introducing boring theory on how the flyweight pattern works. You’ll have the chance to learn and test many practical examples related to the referenced pattern, so you can quickly start applying it in your own PHP applications.

A final note before I proceed further: all the examples that you’ll see here will be developed with PHP 5, but they can be easily modified to work with PHP4 as well.

Having clarified that point, let’s find out together how to implement flyweight classes with PHP. It’s going to be instructive and fun!

{mospagebreak title=Defining a target class}

To demonstrate a practical implementation of the flyweight design pattern with PHP 5, I’m going to start by creating a target class. This class will be used by a flyweight object to keep instances of that class limited to a specified number.

As you’ll see, any attempt to create new instances of the target class will result in returning the same object to calling code. Now, are you starting to understand how the flyweight pattern works? I’m sure you are!

Having explained the logic that I plan to follow in this case, here is the signature of the mentioned target class. It is tasked with constructing text input boxes as part of a form generator system. Have a look at it:

// define ‘TextInputBox’ class
class TextInputBox{
   private $name;
   private $size;
   private $maxlength;
   // assign default values for properties of input box
   public function __construct($name=’default_name’,$size=16,
   $maxlength=32){
     if(!preg_match("/[a-zA-Z]+/",$name)){
       throw new Exception(‘Invalid value for name property!’);
     }
     if(!is_int($size)||$size<0||$size>32){
       throw new Exception(‘Invalid value for size property!’);
     }
     if(!is_int($maxlength)||$maxlength<16||$maxlength>64){
       throw new Exception(‘Invalid value for maxlength
property!’);
     }
     $this->name=$name;
     $this->size=$size;
     $this->maxlength=$maxlength;
   }
   // get (X)HTML markup of input text box  
   public function getHTML(){
     return ‘<input type="text" name="’.$this->name.’"
size="’.$this->size.’" maxlength="’.$this->maxlength.’" />’;
   }
}

As you can see, the signature for the above “TextInputBox” class is really simple to grasp. In short, all this class does is display a regular text input box, which comes in handy for constructing online forms.

Now that you have seen the definition for the previous target class, let me go one step further and create another one. This new class will be aimed specifically at displaying a conventional submit button, so it’s possible to build programmatically a simple contact form.

The definition for this brand new class is listed below, so pay attention to it:

// define ‘SubmitButton’ class
class SubmitButton{
   private $name;
   private $value;
   public function __construct($name=’default_name’,$value=’Send
Data’){
     if(!preg_match("/[a-zA-Z]+/",$name)){
       throw new Exception(‘Invalid value for name property!’);
     }
     if(!preg_match("/[a-zA-Z]+/",$value)){
       throw new Exception(‘Invalid argument for value
property!’);
     }
     $this->name=$name;
     $this->value=$value;                  
   }
   // get (X)HTML markup of submit button  
   public function getHTML(){
     return ‘<input type="submit" name="’.$this->name.’"
value="’.$this->value.’" />’;
   }
}

So far, so good. At this moment, I created two simple classes that are capable of rendering different elements of a web form. The question that comes up now is: how can they be put to work in tandem? That’s a good question!

To answer it, below I coded a short script that displays a simple contact form by using the two previous classes, which is comprised of three input boxes and the corresponding submit button as well. Here is the script in question:

try{
   // instantiate input text box objects
   $nameBox=new TextInputBox(‘name’);
   $addressBox=new TextInputBox(‘address’);
   $emailBox=new TextInputBox(‘email’);
   // instantiate submit button
   $subButton=new SubmitButton(‘send’);
   // display form
   echo ‘<form>’."n".’Name ‘.$nameBox->getHTML().’<br />’."n".’Address ‘.$addressBox->getHTML().’<br />’."n".’Email ‘.$emailBox->getHTML().’<br />’."n".$subButton->getHTML()."n".’</form>’;
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

As demonstrated above, the pair of classes that I created before were used to display a basic contact form that contains three input boxes, handy for letting users enter their respective first and last names, as well as their email addresses. So far, nothing unexpected, right?

But now, let me ask you the following question: what if you want to build a form generator application that only creates three instances of the previous “InputTextBox” class, no matter how many times you try to instantiate new objects?

Well, that’s where the flyweight pattern comes in. It’s possible to define a factory class that only returns to calling code, three instances of the same “InputTextBox” class that you learned previously. This implies that the instantiation of objects would be completely balanced inside the application.

Now, things are getting really exciting! Therefore, in the next few lines I’m going to show you how to create a flyweight factory class. As I stated before, it will be responsible for returning three unique instances of the previous “InputTextBox” class.

As usual, to learn how this flyweight class will be defined, read the following section.

{mospagebreak title=Defining a flyweight factory class}

In accordance with the concepts that I expressed in the previous section, applying the flyweight pattern here is only a matter of defining a factory class that will be capable of returning to client code only three instances of the “InputTextBox” class that was previously defined.

In fact, this sounds like a simple thing to do, but this theory must be translated into a fully-functional class. Thus, in response to this requirement, below I defined a flyweight factory class. It obviously returns three text input objects to calling code. The signature for this brand new class is as follows:

// define ‘FlyweightFormElementFactory’ class
class FlyweightFormElementFactory{
   private $formElements=array();
   public function __construct(){
     $this->formElements['name']=NULL;
     $this->formElements['address']=NULL;
     $this->formElements['email']=NULL;
   }
   // return only three text input boxes
   public function fetchFormElement($elementName){
     if($elementName!=’name’&&$elementName!=
        ‘address’&&$elementName!=’email’){
       throw new Exception(‘Invalid name for form element!’);
     }
     if($this->formElements[$elementName]==NULL){
       $this->formElements[$elementName]=new TextInputBox
($elementName);
     }
     return $this->formElements[$elementName];
   }
}

As you can see, the above flyweight factory class exposes only one method (aside from the constructor), called “fetchFormElement(),” which is responsible for creating three instances of the respective “TextInputBox” class created previously.

But what’s the point of doing this? Well, if you use the above factory class to build a simple contact form, it always returns the same input text objects to calling code, no matter how many times the class is invoked across the same application. Logically, this prevents the unnecessary instantiation of objects that aren’t really required, in this way improving the overall performance of any application. Pretty good, isn’t it?

However, once you understand properly how the previous flyweight factory class works, there another step to make in order to demonstrate the functionality of the class in question.

Therefore, in the following section I’m going to set up a practical example that will show you how to use the previous flyweight factory class to create a basic online form that only contains three input boxes.

Want to see how this will be achieved? Okay, go ahead and read the next few lines. I’ll be there, waiting for you.

{mospagebreak title=Seeing the flyweight pattern in action}

To demonstrate the functionality provided by the flyweight factory class that I built in the prior section, first I’m going to define a generic form generator class for constructing online forms, and then I’m going to develop an example in which all the classes are put to work together.

As you’ll see shortly, applying the flyweight design pattern will allow us to construct a basic contact form that only contains the three input fields that you saw previously. In accordance with the logic followed by the pattern in question, any attempt to create new form objects will be refused, keeping the creation of objects completely in equilibrium.

Having said that, here is the signature that corresponds to the form generator class:  

// define ‘FormGenerator’ class
class FormGenerator{
   private $method=’post’;
   private $action=’processform.php’;
   private $formElements=array();
   public function addFormElement(TextInputBox $formElement){
     $this->formElements[]=$formElement;
   }
   // fetch (X)HTML markup of web form
   public function displayForm(){
     $html=’<form method="’.$this->method.’" action="’.$this-
>action.’">’;
     foreach($this->formElements as $formElement){
       $html.=$formElement->getHTML().’<br />’;
     }
     $html.=’<input type="submit" value="Send Data" /></form>’;
     return $html;
 
  }
}

Now that you know how the above form generator class has been defined, have a look at the following example, which builds a simple contact form by using the flyweight factory class. As you may guess, this form is comprised of only the three basic fields that I explained previously:

 // example building a web form using the Flyweight design pattern
try{
   // instantiate ‘FlyweightFormElementFactory’ object
   $flyweightFormElemFactory=new FlyweightFormElementFactory();
   // instantiate input text boxes
   $flyweightNameBox=$flyweightFormElemFactory->fetchFormElement
(‘name’);
   $flyweightAddressBox=$flyweightFormElemFactory-
>fetchFormElement(‘address’);
   $flyweightEmailBox=$flyweightFormElemFactory->fetchFormElement
(‘email’);      
   // instantiate ‘FormGenerator’ object
   $formGenerator=new FormGenerator();
   // add input text objects to form generator
   $formGenerator->addFormElement($flyweightNameBox);
   $formGenerator->addFormElement($flyweightAddressBox);
   $formGenerator->addFormElement($flyweightEmailBox);
   echo $formGenerator->displayForm();
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

As shown above, the sample contact form is built by utilizing the functionality of the previous flyweight factory class, in combination with the form generator. Logically, this process is quite simple to follow, and certainly there’s nothing special about it.

However, see what happens when I try to instantiate a new text input box, aside from the ones allowed by the flyweight factory class:

// try instantiating a different input text box (triggers an
exception)
// $flyweightNameBox1=$flyweightFormElemFactory->fetchFormElement
(‘postalcode’);

In this case the previous script throws an exception and the program’s execution is halted. In addition, here’s another situation where I try to create two input boxes called “name.” In this case, the script returns two identical objects, as shown below:

// instantiate two identical ‘name’ input boxes
$flyweightNameBox1=$flyweightFormElemFactory->fetchFormElement
(‘name’);
$flyweightNameBox2=$flyweightFormElemFactory->fetchFormElement
(‘name’);
if($flyweightNameBox1===$flyweightNameBox2){
  throw new Exception(‘Input text boxes objects are the same!’);
}

Now, it should be pretty clear to you how the flyweight pattern works, since in the above example only three instances of the respective “InputTextBox” class are allowed. Any other attempts to create different objects are simply rejected by the flyweight factory class.

Now, do you realize how a PHP application can control the instantiation of classes via this useful pattern? I bet you do!

To wrap up

In this first installment of the series, I introduced the key concepts of the flyweight design pattern, and showed you how to apply them in the context of a form generator application.

In the course of the final part of the series, I’m going to teach you how to apply this pattern to develop a web page generator system. I don’t think you’ll want to miss it!

Google+ Comments

Google+ Comments