PHP: Effects of Wrapping Code in Class Constructs

In this first part of a two-part tutorial, I use a somewhat contrived example to show why you should avoid coding static helper classes in PHP.

Let’s be honest: how many times have you found yourself writing a custom static helper class, or putting your hands eagerly on one that came bundled with a framework, from the many available out there? If you’re anything like me, the answer will be at least … a few (remember that the first step to healing is admitting you have a problem). Static helpers seem to be a great idea at first glance, as they’re reusable components that don’t require any kind of expensive instantiation for doing common tasks, such as determining base URLs and paths or validating incoming data. But the sad and unavoidable truth is in many cases they’re simply wrappers for procedural code, which has been elegantly hidden behind a “class” construct.

So what’s wrong with this? Well, even in the most harmless situations, when you use a static helper that produces a deterministic output, you’re actually throwing away the advantages that OOP provides. First and foremost, you can’t exploit the functionality of Polymorphism, which is a serious drawback indeed. Also, while it’s possible to further extend a static helper via Inheritance without infringing the Liskov Substitution Principle, you can’t create new helpers without breaking up existing client code, hence violating the Open/Closed Principle.

This doesn’t mean, though, that you should stop using your current helpers or completely avoid building new ones in the future. However, with a little willpower and the use of good object-oriented practices, you can easily create “instantiable” helpers. These will not only be shielded from the aforementioned issues, but will also be able to be injected into other objects’ internals. Add to this the ability to be  tested in isolation, mocked up and so forth, and you’ll end up with a firm groundwork that will let you build more robust and solid OO applications.

As usual, the best way to demonstrate why static helper classes can make your life a lot harder (and how easy it is to turn them into “injectable” instances) is by example. In this two-part tutorial I’ll be setting up a few in PHP (which can be ported to other languages, of course) to help you grasp the pitfalls of this approach, and how to fix them.

Building a Static Validator Class in PHP

As I explained at the beginning, it’s fairly simple to prove why static helper classes can cause a lot of headaches, especially when building scalable object-oriented applications. The first step of this proof is to create a trivial helper that will be responsible for validating different types of input data, such as integers and floats, URLs and email addresses.

Please take a look at my sample validator helper, whose implementation looks like this:

(Library/Helper/Validator.php)

<?php

namespace LibraryHelper;

class Validator
{
    private function __construct(){}
   
    /**
     * Validate an email address
     */
    public static function validateEmail($email)
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL);   
    }
   
    /**
     * Validate a URL
     */
    public static function validateUrl($url)
    {
        return filter_var($url, FILTER_VALIDATE_URL);  
    }
   
    /**
     * Validate a float number
     */
    public static function validateFloat($value)
    {
        return filter_var($value, FILTER_VALIDATE_FLOAT);
    } 
   
    /**
     * Validate an integer number
     */ 
     public static function validateInteger($value)
     {
         return filter_var($value, FILTER_VALIDATE_INT);
     }     
}

There’s not much to say about the above “Validator” class, as it only implements a set of static methods, which use a few PHP filters to validate the previously mentioned data types. However, don’t let the naive nature of this static validator fool you, since it comes with some issues worth noting. First, it’s nothing but a bag of procedural functions, which don’t expose explicit pre/post conditions or even class invariants.

Secondly, the only way to extend its current functionality is by means of Inheritance. This naturally infringes the commandments of the Open/Closed paradigm, as no instances that adhere to some interface can be passed around. And last but not least, the class is clearly doing too many things, hence breaking the Single Responsibility principle.     

For obvious reasons, my seemingly inoffensive helper class is in reality a wild creature running through distant woods instead of treading the straight and narrow road of good object-oriented practices. For the sake of completeness, however, below I wrote a simple script that shows how to use it for checking some trivial data. Here it is:   

<?php

// include the validator helper
require_once __DIR__ . ‘/Helper/Validator.php';

use LibraryHelperValidator as Validator;

// validate a URL
if (!Validator::validateUrl(‘http://www.devshed.com’)) {
    echo ‘The supplied URL is invalid';
}

// validate an email address
if (!Validator::validateEMail(‘user@domain.com’)) {
    echo ‘The supplied email address is invalid.';
}

// validate a float number   
if (!Validator::validateFloat(2.5)) {
    echo ‘The supplied value is an invalid float number.';
}

// validate an integer number
if (!Validator::validateInteger(10.5)) {
    echo ‘The supplied value is an invalid integer number.';
}

/* displays the following

The supplied value is an invalid integer number.

*/

Even though the helper actually does its business as one might expect, it’s clear to see its procedural roots. But, there’s no need to start pulling our hair out, as turning the class into a fully-extendable, object-oriented compliant structure is a simple process. In fact, the entire “conversion” is reduced to breaking the class into several instantiable subclasses, which will be implementers of the same interface.

{mospagebreak title=Converting the Helper}

As usual, the most effective way to shed some light on this process is by means of some concrete code samples. So take a look at the one below, which defines the aforementioned interface:

(Library/Helper/ValidatorInterface.php)

<?php

namespace LibraryHelper;

interface ValidatorInterface
{
    /**
     * Validate the given value
     */
    public function validate(); 
}     
     
As you can see above, the contract defined by this brand new interface is really simple. Its existence is a more efficient solution than the static class created previously, as it allows us to not only to apply the “Coding to an interface, not to an implementation” principle, but permits us to easily build different kinds of validators without breaking the functionality of existing client code.

With this interface already declared, the next step toward the creation of separate, instantiable validators is to encapsulate their common functionality in an abstract class. Not surprisingly, I called this one “AbstractValidator” and its definition is as follows:  

(Library/Helper/AbstractValidator.php)

<?php

namespace LibraryHelper;

abstract class AbstractValidator
{
    const DEFAULT_ERROR_MESAGE = ‘The supplied value is invalid.';
    protected $_value;
    protected $_errorMessage = self::DEFAULT_ERROR_MESAGE;
   
    /**
     * Constructor
     */
    public function __construct($value = null, $errorMessage = null)
    {  
        if ($value !== null) {
            $this->setValue($value);
        }
        if ($errorMessage !== null) {
           $this->setErrorMessage($errorMessage);
        }
    }
   
    /**
     * Set the value to be validated
     */
    public function setValue($value)
    {
        $this->_value = $value;
    }
   
     /**
     * Get the inputted value
     */
    public function getValue()
    {
        return $this->_value;
    }
     
    /**
     * Set the error message
     */
    public function setErrorMessage($errorMessage)
    {
        if (!is_string($errorMessage) || empty($errorMessage)) {
            throw new InvalidArgumentException(‘The error message is invalid. It must be a non-empty string.’);
        }
        $this->_errorMessage = $errorMessage;
    }
   
    /**
     * Get the error message
     */
    public function getErrorMessage()
    {
        return $this->_errorMessage;
    }
   
    /**
     * Reset the error message to the default value
     */
    public function resetErrorMessage()
    {
        $this->_errorMessage = self::DEFAULT_ERROR_MESAGE;
    }       
}

The source code of the above abstract parent speaks for itself. This base class simply implements a couple of basic mutators along with a getter (aside from the constructor), which allow us to assign and retrieve the error message associated with a particular validator. It’s nothing especially complex, in reality.

With the previous class up and running already, it’s time to recap and see what’s been achieved so far. One the one hand, there exists a segregated interface, which makes spawning new validators a breeze. On the other hand, the earlier class is nothing but a simple container, which hides functionality shared by the validators in question (except for the validation process itself, of course).

If you’re like me, you’re probably wondering how to build up a set of concrete, more granular validators to replace the previous “does-all” static helper. Well, the process would be as easy as subclassing the abstract parent and implementing the “ValidatorInterface” interface.

But I’m getting ahead of myself, since the full details of this process will be covered in depth in the next installment.       

Closing Remarks

In this first part of a two-part tutorial, I used a fairly contrived example to demonstrate why you should avoid coding static helper classes in PHP, regardless of whether you’re building an object-oriented framework, a custom library or your next killer application.

Even if you’re not a strong worshipper of the SOLID principles, the side effects generated by this kind of helper are numerous and detrimental. In the name of plain common sense and good programming habits, try to stay away from them simply by making them non-static.

If you want to see how I plan to fix my own static validator, and turn it into a set of polymorph instances which can be injected, unit-tested and passed around, don’t miss the final part!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort