Home arrow PHP arrow Page 2 - The PHP Plug-in Pattern

Implementing the Plug-in pattern - PHP

In this first part of a series, I introduce the key concepts that surround the implementation of the Plug-in design pattern in PHP. I also show you how to use it to build an easily extensible application. The sample program in this case will render a few simple HTML widgets on screen, such as divs and paragraphs, but this functionality can be easily extended to other elements as well.

TABLE OF CONTENTS:
  1. The PHP Plug-in Pattern
  2. Implementing the Plug-in pattern
By: Alejandro Gervasio
Rating: starstarstarstarstar / 2
January 19, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

In fact, solving the seemingly-complex scenario discussed in the previous section is ridiculously simple, thanks to the use of the "Plug-in" paradigm. Remember that at the beginning, I stated that this pattern often requires the use of an interface? Well, to make the earlier renderer accept any type of "renderable" object, the first change that I'm going to introduce will be the incorporation of a new interface, not surprisingly called "Renderable" as well.

The interface looks like this:

(Render/Renderable.php)

<?php

namespace Render;

interface Renderable
{
    public function render(); 
}

Even though the definition of the above interface seems to be a rather irrelevant fact at first glance, the impact that it introduces into the "plugability" of the previous rendering application is remarkable. Not convinced yet? Then take a look at the revamped implementations of the following HTML classes, which should make you change your mind:

(Html/AbstractHtmlElement.php)

<?php

namespace Html;

abstract class AbstractHtmlElement
{
    protected $_content;
    protected $_id;
    protected $_class;
   
    /**
     * Constructor
     */
    public function __construct($content, $id = '', $class = '')
    {
        if (is_string($content)) {
           $this->_content = $content;
        }
        if (is_string($id) && !empty($id)) {
            $this->_id = $id;
        }
        if (is_string($class) && !empty($class)) {
            $this->_class = $class;
        }   
    }   
}

 

(Html/Div.php)

<?php

namespace Html;
use Render;

class Div extends AbstractHtmlElement implements RenderRenderable
{
    /**
     * Render the Div element
     */
    public function render()
    {
        $html = '<div';
        if ($this->_id) {
            $html .= ' id="' . $this->_id . '"';
        }
        if ($this->_class) {
           $html .= ' class="' . $this->_class . '"';
        }
        $html .= '>' . $this->_content . '</div>' . "n";
        return $html;
    }
}

 

(Html/Paragraph.php)

<?php

namespace Html;
use Render;

class Paragraph extends AbstractHtmlElement implements RenderRenderable
{
    /**
     * Render the Paragraph element
     */
    public function render()
    {
        $html = '<p';
        if ($this->_id) {
            $html .= ' id="' . $this->_id . '"';
        }
        if ($this->_class) {
           $html .= ' class="' . $this->_class . '"';
        }
        $html .= '>' . $this->_content . '</p>' . "n";
        return $html;
    }
}

A couple of interesting things are happening here. The first one is the definition of a whole new class called "Paragraph," which is responsible for returning to client code the markup corresponding to the identically-named HTML element. The second one, and by far the most relevant, is that this class and the earlier "Div" are now implementers of the "Renderable" interface, while at the same time extending the functionality of its abstract parent.

This apparently subtle change is actually the soul and body of the "Plug-in" pattern. It allows you to create client classes that can be fed any type of "renderable" element, not only the ones that display HTML code. This concept can be seen more clearly in the enhanced implementation of the "Renderer" class. Take a peek at it:

(Render/Renderer.php)

<?php

namespace Render;

class Renderer
{
    protected $_elements = array();
   
    /**
     * Add a single renderable element
     */
    public function addElement(Renderable $element)
    {
        $this->_elements[] = $element;
        return $this;
    }
   
    /**
     * Remove a renderable element
     */
    public function removeElement(Renderable $element)
    {
        if (in_array($element, $this->_elements, true)) {
            $elements = array();
            foreach ($this->_elements as $_element) {
                if ($element !== $_element) {
                    $elements[] = $_element;
                }
            }
            $this->_elements = $elements;
        }
    }
   
    /**
     * Add multiple renderable elements
     */
    public function addElements(array $elements)
    {
        if (!empty($elements)) {
            foreach ($elements as $element) {
                $this->addElement($element);
            }
        }
    }
   
    /**
     * Render all the inputted renderable elements
     */
    public function render()
    {
        $output = '';
        if (!empty($this->_elements)) {
            foreach ($this->_elements as $_element) {
                $output .= $_element->render();
            }
        }
        return $output;
    }    
}

Effectively, the renderer now takes, through its "addElement()" method, any object that implements the "Renderable" interface. In this way, it implements a truly "pluggable" system whose functionality can be extended via third-party classes. At this point, do you spot the benefits of implementing the "Plug-in" pattern in PHP? I guess you do!

However, the best way to see if my claim is really true is by creating an example that uses the amended versions of the previous classes. That's precisely what I plan to do in the following section, so keep reading.

Seeing the plug-in pattern in action: building a final example

If you're anything like me, you want to see a concrete example that puts the earlier classes (and the "Renderable" interface, of course) to work side by side. Below I created a simple one for you, which shows in a nutshell the functionality of the "Plug-in" pattern. Here it is:

<?php

use HtmlDiv as Div,
    HtmlParagraph as Paragraph,
    RenderRenderer as Renderer;
   
// include the autoloader
require_once 'Autoloader.php';
Autoloader::getInstance();

// create some HTML elements
$div = new Div('This is the sample content for the div element.', 'one_id', 'one_class');
$par = new Paragraph('This is the sample content for the paragraph element.', 'another_id', 'another_class');

// create the renderer and add the previous elements to it
$renderer = new Renderer;
echo $renderer->addElement($div)
              ->addElement($par)
              ->render();

/* displays the following

<div id="one_id" class="one_class">This is the sample content for the div element.</div>
<p id="another_id" class="another_class">This is the sample content for the paragraph element.</p>

*/

While it's valid to point out that the output generated by the above script is pretty primitive (after all, it simply echoes a div and a paragraph to the browser), it illustrates how the use of the "Plug-in" pattern permits you to create applications that can be easily extended. In the previous example, a couple of renderable HTML objects have been passed to an instance of the "Renderer" class.

It's also possible, however, to feed the pertinent class any other kind of renderable element, such as an object that generates PDF content, or one that renders JPG, GIF and PNG images. I guess you get the picture. And best of all, this enhancement process can be accomplished without having to refactor the implementation of the renderer.

So what are you waiting for? Build your own renderable objects and inject them into the generic renderer. You'll be more than pleased with the results that you'll get, believe me.

Closing thoughts

In this first part of the series, I provided you with a quick introduction to the key concepts that surround the implementation of the Plug-in design pattern in PHP, and also showed how to take advantage of its benefits for building an easily extensible application. In this case, the sample program rendered on screen a few simple HTML widgets, such as divs and paragraphs, but this functionality can be easily extended to other elements as well.

To demonstrate this concept more clearly, in the next article in this series I'm going to add a brand new class to this application. It will be responsible for rendering some basic JavaScript alert boxes. Thanks to the Plug-in pattern, though, this task will be performed without having to modify a single portion of the application's source code.

Don't miss the next tutorial! 

 



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: