Hot File

The Open/Closed Principle in PHP

View: 217    Dowload: 0   Comment: 0   Post by: hanhga  
Author: none   Category: Forum PHPBB, VBB   Fields: Other

0 point/2 review File has been tested

As usual, a good way to grasp what’s actually behind the curtain of the principle and how to take advantage of its benefits is by example. In this article I’ll be setting up a few approachable ones in an attempt to unveil the principle’s driving forces.

Introduction

As usual, a good way to grasp what’s actually behind the curtain of the principle and how to take advantage of its benefits is by example. In this article I’ll be setting up a few approachable ones in an attempt to unveil the principle’s driving forces.

Implementing a Non-Polymorphic HTML Renderer

While the idea stems mostly from the pragmatism of experience, sometimes it’s easier to understand a concept by first showing the wrong way of doing something. In this case, I’m going to cling to that pragmatic approach and demonstrate why the implementation of system modules that aren’t designed around the idea of “Modification Closure” stated by the Open/Closed Principle may cause an explosion of fragility/rigidity artifacts.

Say we need to build a quick and dirty HTML renderer module capable of dumping a few HTML objects modeling divs, paragraphs, and the like. Following an irreverently sloppy and non-polymorphic approach, the corresponding HTML classes and the consumer module could be written as follows:

<?php
namespace LibraryView;

class HtmlDiv
{
    private $text;
    private $id;
    private $class;

    public function __construct($text, $id = null, $class = null) {
        $this->setText($text);
        if ($id !== null) {
            $this->setId($id);
        }
        if ($class !== null) {
            $this->setClass($class);
        }
    }

    public function setText($text) {
        if (!is_string($text) || empty($text)) {
            throw new InvalidArgumentException(
                "The text of the element is invalid.");
        }
        $this->text = $text;
        return $this;
    }

    public function setId($id) {
        if (!preg_match('/^[a-z0-9_-]+$/', $id)) {
            throw new InvalidArgumentException(
                 "The attribute value is invalid.");
        }
        $this->id = $id;
        return $this;     
    }

    public function setClass($class) {
        if (!preg_match('/^[a-z0-9_-]+$/', $id)) {
            throw new InvalidArgumentException(
                 "The attribute value is invalid.");
        }
        $this->class = $class;
        return $this;     
    }

    public function renderDiv() {
        return '<div' .
            ($this->id ? ' id="' . $this->id . '"' : '') .
            ($this->class ? ' class="' . $this->class . '"' : '') .
            '>' . $this->text . '</div>';
    }
}
<?php
namespace LibraryView;

class HtmlParagraph
{
    private $text;
    private $id;
    private $class;

    public function __construct($text, $id = null, $class = null) {
        $this->setText($text);
        if ($id !== null) {
            $this->setId($id);
        }
        if ($class !== null) {
            $this->setClass($class);
        }
    }

    public function setText($text) {
        if (!is_string($text) || empty($text)) {
            throw new InvalidArgumentException(
                "The text of the element is invalid.");
        }
        $this->text = $text;
        return $this;
    }

    public function setId($id) {
        if (!preg_match('/^[a-z0-9_-]+$/', $id)) {
            throw new InvalidArgumentException(
                 "The attribute value is invalid.");
        }
        $this->id = $id;
        return $this;     
    }

    public function setClass($class) {
        if (!preg_match('/^[a-z0-9_-]+$/', $id)) {
            throw new InvalidArgumentException(
                 "The attribute value is invalid.");
        }
        $this->class = $class;
        return $this;     
    }

    public function renderParagraph() {
        return '<p' .
            ($this->id ? ' id="' . $this->id . '"' : '') .
            ($this->class ? ' class="' . $this->class . '"' : '') .
            '>' . $this->text . '</p>';
    }
}
<?php
namespace LibraryView;

class HtmlRenderer
{
    private $elements = array();

    public function __construct(array $elements = array()) {
        if (!empty($elements)) {
            $this->addElements($elements);
        }
    }

    public function addElement($element) {
        $this->elements[] = $element;
        return $this;
    }

    public function addElements(array $elements) {
        foreach ($elements as $element) {
            $this->addElement($element);
        }
        return $this;
    }

    public function render() {
        $html = "";
        foreach ($this->elements as $element) {
            if ($element instanceof HtmlDiv) {
                $html .= $element->renderDiv();
            }
            else if ($element instanceof HtmlParagraph) {
                $html .= $element->renderParagraph();
            }
        }
        return $html;
    }
}

The responsibilities of HtmlDiv and HtmlParagraph are limited to rendering the corresponding HTML elements based on a few common input arguments, such as the inner text, and the “id” and “class” attributes.

The class that begs being put under a spotlight is the contrived HtmlRenderer, which certainly can be extended further down the road either via Inheritance or Composition (read open for extension). Exposing such virtue to the outside world, what could be wrong with the renderer then? Well, its most clumsy facet rests on the fact that its level of closure for modification is in this case just a bluff because the HTML objects it handles are non-polymorphic. In its current state the class is just capable of rendering batches of HtmlDiv and HtmlParagraph objects and …sorry, nothing else. If we ever want to add a new object type to its repertoire, the render() method needs to be refactored and polluted with more conditionals. To express this in the Open/Closed Principle’s terms, the class is by no means closed for modification.

Appealing to the Benefits of Polymorphism

Implementing an effective solution is be a two-step process: first and foremost, the classes responsible for engendering the HTML objects should be turned into polymorphic structures that adhere to a shared contract. Then the HtmlRenderer class should be refactored to handle any implementer of the contract without checking explicitly if it belongs to a certain type.

A segregated interface that gets the job done nicely is this:

<?php
namespace LibraryView;

interface HtmlElementInterface
{
    public function render();
}

With this contract in place, now it’s time to do some quick clean up and encapsulate all the logic shared by the HTML classes inside the boundaries of an abstract Layer Supertype.

<?php
namespace LibraryView;

abstract class AbstractHtmlElement implements HtmlElementInterface
{
    protected $text;
    protected $id;
    protected $class;

    public function __construct($text, $id = null, $class = null) {
        $this->setText($text);
        if ($id !== null) {
            $this->setId($id);
        }
        if ($class !== null) {
            $this->setClass($class);
        }
    }

    public function setText($text) {
        if (!is_string($text) || empty($text)) {
            throw new InvalidArgumentException(
                "The text of the element is invalid.");
        }
        $this->text = $text;
        return $this;
    }

    public function setId($id) {
        $this->checkAttribute($id);
        $this->id = $id;
        return $this;     
    }

    public function setClass($class) {
        $this->checkAttribute($class);
        $this->class = $class;
        return $this;     
    }

    protected function checkAttribute($value) {
        if (!preg_match('/^[a-z0-9_-]+$/', $value)) {
            throw new InvalidArgumentException(
                "The attribute value is invalid.");
        }
    }
}

Things are now looking more appealing as we’ve managed to put implementation that’s common to all of the HTML objects beneath the shell of a supertype. Though simplistic, this change automatically turns the revamped versions of the HtmlDiv and HtmlParagraph classes into slim implementers of the same interface:

<?php
namespace LibraryView;

class HtmlDiv extends AbstractHtmlElement
{    
    public function render() {
        return '<div' .
            ($this->id ? ' id="' . $this->id . '"' : '') .
            ($this->class ? ' class="' . $this->class . '"' : '') .
            '>' . $this->text . '</div>';
    }
}
<?php
namespace LibraryView;

class HtmlParagraph extends AbstractHtmlElement
{    
    public function render() {
        return '<p' .
            ($this->id ? ' id="' . $this->id . '"' : '') .
            ($this->class ? ' class="' . $this->class . '"' : '') .
            '>' . $this->text . '</p>';
    }
}

Considering that HtmlDiv and HtmlParagraph are now beautifully polymorphic structures that honor a common contract, it’s simple to refactor the pertaining HTML renderer into a consumer of any implementer of the HtmlElementInterface interface:

<?php
namespace LibraryView;

class HtmlRenderer
{
    private $elements = array();

    public function __construct(array $elements = array()) {
        if (!empty($elements)) {
            $this->addElements($elements);
        }
    }

    public function addElement(HtmlElementInterface $element) {
        $this->elements[] = $element;
        return $this;
    }

    public function addElements(array $elements) {
        foreach ($elements as $element) {
            $this->addElement($element);
        }
        return $this;
    }

    public function render() {
        $html = "";
        foreach ($this->elements as $element) {
            $html .= $element->render();
        }
        return $html;
    }
}

I’m aware that the new implementation of the HtmlRenderer class is a far cry from being mind blowing, but still it’s now a solid module that adheres to the Open/Closed Principle’s predicates. Furthermore, not only does it expose a nice level of closure for modification, as it’s feasible to feed it at runtime with multiple implementers of the HtmlElementInterface interface without amending a single chunk of it, but this feature on its own proves that it’s entirely open for extension as well. Feel free to pat yourself on the back because we’ve won the battle on two fronts!

Here’s how the module could be put to work for rendering a couple of HTML objects:

<?php
use LibraryLoaderAutoloader,
    LibraryViewHtmlDiv,
    LibraryViewHtmlParagraph,
    LibraryViewHtmlRenderer;

require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader();
$autoloader->register();

$div = new HtmlDiv("This is the text of the div.", "dID", "dClass");

$p = new HtmlParagraph("This is the text of the paragraph.", "pID", "pClass");

$renderer = new HtmlRenderer(array($div, $p));
echo $renderer->render();

 

The Open/Closed Principle in PHP

The Open/Closed Principle in PHP Posted on 12-04-2016  As usual, a good way to grasp what’s actually behind the curtain of the principle and how to take advantage of its benefits is by example. In this article I’ll be setting up a few approachable ones in an attempt to unveil the principle’s driving forces. 5/10 217

Comment:

To comment you must be logged in members.

Files with category

  • Input Validation Using Filter Functions with php

    View: 340    Download: 0   Comment: 0   Author: none  

    Input Validation Using Filter Functions with php

    Category: Forum PHPBB, VBB
    Fields: Other

    2.25/2 review
    Filter functions in PHP might not be sexy, but they can improve the stability, security, and even maintainability of your code if you learn how to use them correctly.

  • The Open/Closed Principle in PHP

    View: 217    Download: 0   Comment: 0   Author: none  

    The Open/Closed Principle in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/2 review
    As usual, a good way to grasp what’s actually behind the curtain of the principle and how to take advantage of its benefits is by example. In this article I’ll be setting up a few approachable ones in an attempt to unveil the principle’s driving...

  • Dependency Injection with Pimple in PHP

    View: 264    Download: 0   Comment: 0   Author: none  

    Dependency Injection with Pimple in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    1.6666666666667/3 review
    In application development, we try to create independent modules so that we can reuse code in future projects. But, it’s difficult to create completely independent modules which provide useful functionality; their dependencies can cause maintenance...

  • Working with Directories in PHP

    View: 382    Download: 0   Comment: 0   Author: none  

    Working with Directories in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.25/2 review
    Let's start with simple listing the contents of a directory. We need three functions to perform this task: opendir(), readdir() and closedir(). The opendir() function takes one parameter, which is the directory we want to read, and returns a...

  • Guide to Email (Text / HTML / Attachments) in PHP

    View: 362    Download: 0   Comment: 0   Author: none  

    Guide to Email (Text / HTML / Attachments) in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/2 review
    At first let's consider how to send a simple text email messages. PHP includes the mail() function for sending email, which takes three basic and two optional parameters.

  • Dynamic Image Generation in PHP

    View: 319    Download: 0   Comment: 0   Author: none  

    Dynamic Image Generation in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/1 review
    At first, have a look at the following script that creates captcha image. Next, we will consider each step of image generation in details.

  • Form Processing with PHP

    View: 580    Download: 0   Comment: 0   Author: none  

    Form Processing with PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.6666666666667/3 review
    Before you can process the information, you need to create an HTML form that will send information to your PHP script. There are two methods for sending data: POST and GET. These two types of sending information are defined in your HTML form...

  • Function in PHP

    View: 475    Download: 0   Comment: 0   Author: none  

    Function in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.5/2 review
    A function is a block of code which can be called from any point in a script after it has been declared. It is basically a compartmentalized PHP script designed to accomplish a single task. Furthermore, code contained within functions is ignored...

 
Newsletter Email

File suggestion for you

File top downloads

logo codetitle
Codetitle.com - library source code to share, download the file to the community
Copyright © 2015. All rights reserved. codetitle.com Develope by Vinagon .Ltd