http://www.developer.com/

Back to article

Implementing Patterns within PHP


April 26, 2004

PHP 5, due for release in the coming weeks, will offer users an abundance of new and enhanced features, yet perhaps none are as appealing as the vast improvements to its object-oriented capabilities. In an earlier article, I introduced these new features, showing you how to improve class management using variable and method scopes, interfaces, abstract classes, and unified constructors and destructors. These enhancements allow you to take a far more disciplined approach to development, incorporating well-documented object-oriented design solutions into your applications, known as design patterns. This article kicks off a several part series on this topic.

In this inaugural article, I have two goals in mind. First, I'll provide a general introduction to design patterns, offering some insight into their purpose, advantages, and interesting history. Second, I'll introduce two patterns, namely the Singleton and the Factory, and offer a PHP-based implementation in the form of an applicable example. In subsequent articles, I'll build upon this material, introducing other key patterns along the way.

Why Patterns?

There's a saying that goes, "Those who forget history are doomed to repeat it." This maxim certainly applies to programming. After all, it wouldn't be a stretch to say that the majority of our efforts are devoted to repeatedly solving a core set of problems. Sure, the goals and languages change, but the underlying mechanisms of our applications do not. Despite this realization, it's commonplace to almost blindly solve these problems as they arise, often with a new solution, rarely with lessons learned. This fact has not been lost on the programming community. In an effort to eliminate an otherwise vast disparity of solutions for such repeatable problems, a well-tested set of blueprints have been defined regarding their resolution. Such blueprints are known as design patterns.

Despite design patterns' profound impact on the programming discipline, it's interesting to note that early thinking on the matter originated in the field of architecture. An architect named Christopher Alexander published numerous works in the 1970's regarding his views on the commonalities of structural features found within well-designed buildings. Two of his seminal books on the topic are "A Pattern Language" and "A Timeless Way of Building", both of which are standard reading on the subject of patterns. In these works, he derides the anarchic, "anything goes" mindset which has gripped the architectural industry over the past century, and sets forth a well-constructed argument in support of the idea that each quality building component, an arch, alcove, and doorway for example, is the result of adherence to a general set of design precepts that embody a set of rules defining its composition. This rationalization served as the catalyst for software developers to start pondering whether a similar approach could be applied to program design. However, it wasn't until the publication of yet another ground-breaking work on design patterns, aptly titled "Design Patterns: Elements of Reusable Object-Oriented Software, that the practice of pattern examination really took hold in the software community.

Published in 1995, "Design Patterns" really laid the groundwork for the widespread study of pattern studies in Computer Science, defining 23 regularly occurring patterns found in object-oriented applications. It's the brainchild of four Computer Science doctorates, namely Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. For many "Design Patterns", known almost synonomously by its nickname, the "Gang of Four" or "GoF" book, ranks among the most prolific programming books ever penned. In addition to the works of Alexander, this book is a required addition to any programmer's bookshelf.

Now that you've been apprised of the basic history and thought process behind design patterns, I'd like to make a foray into the first of several pattern groupings that we'll discuss in this series: creational patterns.

Creational Patterns

Creating flexible, extensible and portable applications is largely dependent upon how well you separate, or decouple, a system from the process involved with object composition, creation and representation. In many cases, its possible to abstract these processes by way of creational patterns, which are intended to lessen the burden of object construction and class referencing through the provision of a general framework. Below, I'll introduce two of the several creational patterns at your disposal, namely the Singleton and the Factory Method.

Singleton Pattern

Sometimes a single instance of a class is all that is required to effectively manage a task. Print spoolers, application logging, and database access are all examples of tasks that work well within such parameters. In each such circumstance, creating multiple instances only results in unnecessary consumption of resources, yet managing such affairs across your entire code base can be distracting and unwieldy. Given such circumstances, rather than attempt to manage that class through external means, it makes sense to place the burden of creation and management of this single instance on the class itself. Consolidating management under this single class effectively creates a single point of access to it, relieving guesswork that would otherwise have to be introduced into the application logic. This strategy is known as the Singleton pattern.

The Singleton pattern possesses two general features:

  • The default class constructor cannot be called. Instead, it will be called through a designated class maintainer method that ensures only one instantiation is available at any given time.
  • A static class member that holds a reference to the existing class resource identifier.

Let's build a PHP class using the Singleton development pattern. Suppose that you're creating a Web-based action game. Of course, there can be one and only one hero, and therefore we need to ensure that only one exists at any given time. Sounds like a perfect reason to use the Singleton pattern! In Listing 1-1, I create a singleton class titled Hero(), and show you how even multiple instantiations yield the same object.

Listing 1-1. A PHP-based singleton pattern implementation

<?phpclass Hero {      private static $exists = NULL;      private $name = "Superhero";      private function __construct() {         // No implementation.      }         static function introduce() {         if (self::$exists === NULL) {            self::$exists = new Hero();         }         return self::$exists;      }      function setName($name) {         $this->name = $name;      }      function getName() {         return $this->name;      }   } #end class Hero   $hero = Hero::introduce();   $hero->setName("Lance");   var_dump($hero);   echo "The hero's name is: ".$hero->getName()."<br />";   $hero2 = Hero::introduce();   var_dump($hero2);   echo "The hero's name is: ".$hero2->getName()."<br />";   $hero2->setName("Bruce");   echo "The hero's name is: ".$hero->getName()."<br />";   echo "The hero's name is: ".$hero2->getName()."<br />";?>

Executing this example yields:

object(Hero)#1 (1) { } The hero's name is: Lance.object(Hero)#1 (1) { } The hero's name is: LanceThe hero's name is: BruceThe hero's name is: Bruce

As you can see by the above output, we're only dealing with one instance of the class throughout the entire example.

Factory Method

Often, a particular application feature can take on a variety of forms. For example, suppose that your Web application offered a letter-writing wizard. Two letter formats are offered: formal and casual. Because its entirely up to the user as to which format is used, instantiation can only take place at runtime. However, how does our system know which class has been instantiated? You might be surprised to know that it doesn't even have to know.

The factory method offers a unified point for instantiating any of several classes, abstracting the process away from the system. These classes implement a certain set of methods which are made known to the system (either via an abstract class or an interface). By forcing this constraint, we can be rest assured that provided an object, the methods executed against it by the system will correspond accordingly. If we later decide to add additional implementations, for example a cover letter and memo format, all we need to do is modify the factory class accordingly. Listing 1-2 implements the letter-wizard application.

Listing 1-2. A PHP-based Factory Method Implementation

<?phpinterface IDocument{   function outputHeader();   function outputBody();   function outputFooter();}class Formal implements IDocument{   public function outputHeader() {      $header = "<p>".date("F d, Y")."</p>";      $header .= "<p>Dear Sir or Madam:</p>";      return $header;   }   public function outputBody($body) {      $body = str_replace(":-)","",$body);      $body = "<p>".$body."</p>";      return $body;   }   public function outputFooter($name) {      return "Sincerely,<br />$name";   }}class Casual implements IDocument {   public function outputHeader() {      return "What's up!<br />";   }   public function outputBody($body) {      $body = "<p>".$body."</p>";      return $body;   }   public function outputFooter($name) {      return "Cya,<br />$name";   }}class DocumentMaker {   function create($type) {      switch($type) {         case 'formal' :            $doctype = new Formal();            break;         case 'casual' :            $doctype = new Casual();            break;         default:            $doctype = new Casual();      }      return $doctype;   }}$docmaker = new DocumentMaker();$docobj = $docmaker->create("formal");echo $docobj->outputHeader();echo $docobj->outputBody("Thank you for lunch today. I appreciate it. :-)");echo $docobj->outputFooter("Jason");?>

Passing "casual" into $docmaker create() method yields:

What's up!Thank you for lunch today. I appreciate it. :-)Cya,Jason

Passing "formal" into the $docmaker create() method yields:

April 15, 2004Dear Sir or Madam:Thank you for lunch today. I appreciate it. Sincerely,Jason

Conclusion

Doing anything cool with PHP and design patterns? Have a question or comment? E-mail me at jason@wjgilmore.com. I'd also like to hear more about your general experience experimenting with PHP 5! Thanks to Mehran Habibi for his valuable input on this article.

About the Author

W. Jason Gilmore (http://www.wjgilmore.com/) is the Open Source Editorial Director for Apress (http://www.apress.com/). He's the author of the upcoming book, PHP 5 and MySQL: Novice to Pro, due out by Apress in 2004. His work has been featured within many of the computing industry's leading publications, including Linux Magazine, O'Reillynet, Devshed, Zend.com, and Webreview. Jason is also the author of A Programmer's Introduction to PHP 4.0 (453pp., Apress). Along with colleague Jon Shoberg, he's co-author of "Out in the Open," a monthly column published within Linux magazine.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date