Open – Close principle / Object – Orientated Design in PHP.

The Open – Closed principle have been formed by Bertrand Meyer in 1988, it can be paraphrased as:

Software entities (let it be classes, modules, functions, etc.) should be open for extending and closed for modification. 

This simple rule means that when we need to change or modify behaviour of our application we should be able to do so not by modifying existing code, but by writing new code instead. 

In PHP it is very easy to break that rule. You always work with code that you can easily modify. Just open a file, whether it is your own or one coming from some third-party library, make your changes – and it done!. PHP offers no formal means of enforcing that rule. 

In other languages, such as C# or C++ you’re often required to work with classes and code closed in libraries. They are compiled to DLLs, you cannot change single line of code in them. 

Make no mistake here, compiling to DLLs does not automatically means you are following open-closed principle. With good object orientated design even when you get the code used to compile DLLs, you should not need to modify it to change your application behaviour. As said earlier following open-closed principle means that changes in your application are achived by writing new code, not modifying existing code-base.

We’ll try to explain open-closed principle with a simple example, which could be used as a starting point in real-world situation. 

In modern web application we’re often required to display images generated on-the-fly. Before image is send to browser we need to state what kind of image we’re sending. 

This is achieved by sending appropriate Content-Type header. For an GIF image we would send :

  1. header("Content-type: image/gif");

for a jpg we send

  1. header(‘Content-type: image/jpg’);

We could write a simple class that does that for us. (Please note that many aspects of sending file content to browser are omitted here for clarity sake.) 

  1. class Image
  2. {
  3.   private $fPath = null;
  4.   public function __construct($fPath)
  5.   {
  6.     $this->fPath = $fPath;
  7.   }
  8.   private function GetFileExtention()
  9.   {
  10.     $strFileName = basename($this->fPath);
  11.     $strExtension = array_pop(explode(".", $strFileName));
  12.     return $strExtension;
  13.   }
  14.   public function SendToBrowser()
  15.   {
  16.     $strFileExtention = $this->GetFileExtention();
  17.     switch ( $strFileExtention )
  18.     {
  19.       case ‘gif’ :
  20.         header("Content-type: image/gif");
  21.         break;
  22.       case ‘jpg’ :
  23.         header("Content-type: image/jpg");
  24.         break;
  25.     }
  26.     $strFileContent = file_get_contents($this->fPath);
  27.     echo $strFileContent;
  28.     die();
  29.   }
  30. }

Task done! We have a reusable class that can be used to send gifs or jpgs to the browser. But this class is not following the principle. 

Why this class breaks the open-closed rule? If we need to send PNG image, we would need to change behaviour of SendToBrowser method and add new case to our switch statement.

The easiest way to stick with the principle is to create abstraction. We need to separate what might vary with what stays constant. In our example the switch statement is the varying part. Let’s try to abstract our Image class.

  1. abstract class AnImage
  2. {
  3.   public function __construct($fPath)
  4.   {
  5.     $this->fPath = $fPath;
  6.   }
  7.   public function SendToBrowser()
  8.   {
  9.     $this->SendFileHeader();
  10.     $strFileContent = file_get_contents($this->fPath);
  11.     echo $strFileContent;
  12.     die();
  13.   }
  14.   public abstract function SendFileHeader();
  15. }

First thing we notice is that our abstract class is a lot simpler. We’re able to get rid of ugly GetFileExtenstion method. We’ve created a much nicer code. Before file is send to browser we call SendFileHeader method. AnImage class does not provide implementation for it, hence it is declared abstract. Concrete classes need to provide implementation for this method. 

Now it is time to create out concrete classes, each representing different file type:

  1. class JpgImage extends AnImage
  2. {
  3.   public function SendFileHeader()
  4.   {
  5.     header("Content-type: image/jpg");
  6.   }
  7. }
  1. class GifImage extends AnImage
  2. {
  3.   public function SendFileHeader()
  4.   {
  5.     header("Content-type: image/gif");
  6.   }
  7. }

In concrete classes we’re implementing abstract SendFileHeader method, sending header appropriate for their file types.

We’ve just created a design that follows open-closed principle. If we need to send images of different types we will create new concrete classes that will implement our abstract SendFileHeader method. Changing our application resulted in writing new code and not changing existing classes. Using similiar approch we can build upon our example to have a desing that will allow us to send any kind of file to a browser.  

Our first implementation of Image class did not follow one other object orientated design principle. The Single Responsibility Principle. But we leave this till we meet again.

This entry was posted in Dev. Bookmark the permalink.

One Response to Open – Close principle / Object – Orientated Design in PHP.

  1. anon says:

    Thanks you, one of best real case use to understand the open-close principle.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This blog is kept spam free by WP-SpamFree.