Only three months between posts. Not bad for me. For my sophmore blog entry I thought I’d share a PHP library implementing this idea by Evans and Fowler. Written for PHP5, it’s a library for defining custom specifications using composition and inheritance.

Let’s look at an example first to see what I’m talking about. Suppose you have a bunch of Person objects that look like this:

1
2
3
4
5
6
class Person {
    public $id;
    public $first_name;
    public $last_name;
    public $age;
}

Now let’s say you need to test them, looking for entities that are valid Person objects, are under 35 years old and have the last name “Johnson.” These conditions might be expressed like this…

1
$p->id >= 1 && $p->age < 35 && $p->last_name == "Johnson"

…and it would satisfy your requirements. But, what if you need this same piece of validation logic in another place? Or perhaps you have another validator that includes all these conditions but also checks to see if the person’s first name is “John?” You could repeat expression shown above, or you could create a specification to be re-used and extended.

1
2
3
4
5
6
7
8
9
class JohnsonSpecification extends AndSpecification {
    public function __constructor() {
        parent::__constructor(
            new AndSpecification(
                new GreaterOrEqualSpecification('id', 1),
                new LesserOrEqualSpecification('age', 34)),
            new EqualSpecification('last_name', 'Johnson'));
    }
}

What we have done here is create a binary tree of tests linked with AND operators to compose a complex specification that can be extended and re-used in our code. To validate a Person object, we would simply test the Person against our new specification:

1
2
3
4
5
6
7
$spec = new JohnsonSpecification();
 
if ($spec->isSatisfiedBy($person)) {
    echo 'Woohoo!';
} else {
    echo 'Doh!';
}

The library implements AND, OR and NOT nodes to compose specifications. The basic tests provided are: starts with, ends with, contains, equals, greater or equal to and lesser or equal to. From these building blocks, you should be able to create a wide range of custom specifications.

Where are they useful? As was shown in this article, specifications can be useful in validating objects. This is particularly useful for services that are passed objects from unknown sources, making sure valid input is received before any processing is done. They can also be used in a similar fashion to filter a stream of objects.

It might also be possible to use specifications to define queries to send to your data layer, though the practicality of this is up for debate. In any case, I hope you find this useful.

Download Specifications Library