PHP: Building Concrete Validators

In this two-part tutorial, I show why the use of static helper classes can be detrimental to building robust and scalable object-oriented applications in PHP (though you should take into account that the concept is language agnostic). I also implement a set of instantiable, fine-grained validators, which can be easily tested in isolation, injected into the internals of other objects, and so forth.

Constructing purely static helper classes can hurt you, especially when you’re trying to build applications that adhere to the principles of good object-oriented programming. As I explained extensively in the first part of this tutorial, static helpers are inflexible structures that can only be extended via Inheritance, and that don’t exploit the benefits of Polymorphism or dependency injection.      

Naturally, the most educational way to learn why static helpers (or any other kind of static class, of course) should be replaced with instantiable classes is through some concrete, easy-to-follow examples. In keeping with this idea, in the aforementioned installment, I went through the implementation of a trivial static helper. It simply validated different types of incoming data, including integer and float numbers, URLs and email addresses too.

Due to the above reasons — and a few others worth noting, like violating the Open/Closed and the Single Responsibility principles — the helper was a pain to use, even in the environment of an example. Imagine what you would have to face in production! Fortunately, turning static helpers into instantiable structures is a snap.

Again, the best way to prove this concept is by example. Hence, I decided to take a more efficient approach and break down my “catch-all” sample helper into a set of discrete classes, with a more refined and limited scope of responsibilities. To be frank, so far I’ve managed to create a single interface implemented by these concrete classes and the abstract parent that they share. Obviously, the next step is to show how the classes look, so that you can see how turning them into non-static structures can yield a host of benefits.

Spawning a Batch of Concrete Validators in PHP

As I just stated in the introduction, it’s ridiculously simple to turn the previous static validator into a set of non-static ones, which can be easily extended, injected and so forth. To accomplish this, I first defined a segregated interface along with an abstract parent, which looked like this: 

(Library/Helper/ValidatorInterface.php)

<?php

namespace LibraryHelper;

interface ValidatorInterface
{
    /**
     * Validate the given value
     */
    public function validate(); 
}     


(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;
    }       
}

Since the above abstract validator and the “ValidatorInterface” interface should be familiar to you, as they were discussed in detail in the preceding article, the next logical step is to create the batch of concrete validators just mentioned. If you’re wondering how they look, well, here they are:

(Library/Helper/EmailValidator.php)

<?php

namespace LibraryHelper;

class EmailValidator extends AbstractValidator implements ValidatorInterface
{
    const DEFAULT_ERROR_MESAGE = ‘The supplied email address is invalid.';
       
    /**
     * Validate an email address
     */
    public function validate()
    {
        return filter_var($this->_value, FILTER_VALIDATE_EMAIL);  
    }    
}


(Library/Helper/FloatValidator.php)

<?php

namespace LibraryHelper;

class FloatValidator extends AbstractValidator implements ValidatorInterface
{
    const DEFAULT_ERROR_MESAGE = ‘The supplied value is an invalid float number.';
   
    /**
     * Validate a float number
     */
    public function validate()
    {
        return filter_var($this->_value, FILTER_VALIDATE_FLOAT);  
    }    
}


(Library/Helper/IntegerValidator.php)

<?php

namespace LibraryHelper;

class IntegerValidator extends AbstractValidator implements ValidatorInterface
{
    const DEFAULT_ERROR_MESAGE = ‘The supplied value is an invalid integer number.';
   
    /**
     * Validate an integer number
     */
    public function validate()
    {
        return filter_var($this->_value, FILTER_VALIDATE_INT);  
    }    
}


(Library/Helper/UrlValidator.php)

<?php

namespace LibraryHelper;

class UrlValidator extends AbstractValidator implements ValidatorInterface
{
    const DEFAULT_ERROR_MESAGE = ‘The supplied URL is invalid.';
   
    /**
     * Validate a URL
     */
    public function validate()
    {
        return filter_var($this->_value, FILTER_VALIDATE_URL);  
    }    
}

While admittedly the implementation of this set of brand new validators is pretty standard and the process can be grasped quickly, you should focus your attention on the benefits achieved with this simple change. First of all, the classes can be instantiated, injected, tested, and easily passed around across the tiers of an application. And second, they perform well-differentiated tasks; each one is responsible for validating only one specific type of data. This is definitely, a big win for the Single Responsibility principle.

So far, so good. Now that you’ve grasped how the validators do their thing, it’s time to see how they can be put to work side by side in a concrete use case. This will be done in the following section.

{mospagebreak title=Validating Incoming Data: Putting the Validators To Work}

As one might expect, putting the earlier validators in action is an extremely simple process, reduced to creating a few instances of them and calling …yes, their “validate()” method. To demonstrate how to accomplish this, below I wrote a basic script which uses the pertinent validators to check some sample input data (to keep things shorter and clearer, I haven’t implemented an autoloader, but you can do that if you want to).

Here’s the script:

<?php

require_once __DIR__ . ‘/Helper/ValidatorInterface.php';
require_once __DIR__ . ‘/Helper/AbstractValidator.php';
require_once __DIR__ . ‘/Helper/UrlValidator.php';
require_once __DIR__ . ‘/Helper/EmailValidator.php';
require_once __DIR__ . ‘/Helper/FloatValidator.php';
require_once __DIR__ . ‘/Helper/IntegerValidator.php';

use LibraryHelperUrlValidator as UrlValidator,
    LibraryHelperEmailValidator as EmailValidator,
    LibraryHelperFloatValidator as FloatValidator,
    LibraryHelperIntegerValidator as IntegerValidator;

// create instances of the validators
$urlValidator = new UrlValidator(‘http://www.devshed.com’);  
$emailValidator = new EmailValidator(‘user@domain.com’);
$floatValidator = new FloatValidator(2.5);
$intValidator = new IntegerValidator(10.5);

// validate a URL
if (!$urlValidator->validate()) {
    echo $urlValidator->getErrorMessage();
}

// validate an email address  
if (!$emailValidator->validate()) {
    echo $emailValidator->getErrorMessage();
}

// validate a float number
if (!$floatValidator->validate()) {
    echo $floatValidator->getErrorMessage();
}

// validate an integer number
if (!$intValidator->validate()) {
    echo $intValidator->getErrorMessage();
}

/* displays the following

The supplied value is an invalid integer number.

*/

While this brand new example is somewhat trivial, it shows how easy it is to utilize the functionality of the previous validators to determine the validity of some incoming data. In this case, client code consumes instances of them directly to perform the process of checking. It’s possible, though, to inject them into other objects (a composite implementation would be a typical situation), or something like that.

Of course, the most relevant detail to notice here is that now we’re working with actual objects, and not simply with procedural code encapsulated within a bunch of static methods. This change itself makes it really worth all the work required to create the originating validator classes and the interface that they implement.

To sum up: even in the simplest use cases (like the one shown above), be sure to build non-static classes. In doing so, you’ll be able to enjoy all of the goodies provided by object-oriented programming, which will translate into more robust and reliable code.

Final Thoughts

Over the course of this two-part tutorial, I showed from a practical standpoint why the use of static helper classes (in this case, a trivial “catch-all” validator) can be detrimental to building robust and scalable object-oriented applications in PHP (you should remember that the concept is language agnostic). In addition, I implemented a set of instantiable, fine-grained validators, which can be easily tested in isolation, injected into the internals of other objects, and so forth.

Even though all of these examples were rather contrived, they made my point about the drawbacks of using purely static classes. In light of this, the next time you get your hands dirty writing your own helpers (or any other class, of course), bear in mind that you’re making your best programs by doing good object-oriented design, which is not class-based. The difference is subtle, but important.

See you in the next PHP development tutorial!

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

chat sex hikayeleri Ensest hikaye