PhpRiot
News Archive
PhpRiot Newsletter
Your Email Address:

More information

Towards A Style Of Contract Programming

Note: This article was originally published at Planet PHP on 14 July 2010.
Planet PHP

There's a programming style I rarely see in the PHP world, but one which I use from my C programming days - programming by contract. It's a very useful technique for writing code that is demonstrably robust, and a useful compliment to unit testing with PHPUnit.

At it's most basic, programming by contract can be summed up as:

  • Does my function or method have inputs that are acceptable to me?
  • Has my function or method generated return data that I'm happy to pass back.

PHP has the assert() method to help with this, but it is deficient and best avoided. I'd like to share the approach I'm currently using for this, to get constructive feedback on how to evolve the style further.

At the heart of this approach lies the constraint. It is a test that must be satisfied; a bit like a runtime unit test. We could do this inline:

function breakMe($inputData = "I am bad data")
{
A A // enforce our constraint
A A if (!is_array($inputData))
A A {
A A A A throw new Exception(aBad data $inputData; expected array()');
A A }
}

a but the problem with that is that it quickly bulks out your code with a lot of repetitive (and avoidable) content. An ideal candidate to make into a function or a method, which could yield:

function constraint_mustBeArray(&$testData)
{
A A if (!is_array($testData))
A A {
A A A A throw new Exception("Constraint failed");
A A }
}

function breakMe($inputData = "I am bad data")
{
A A // our constraint is now in a nice function
A A constraint_mustBeArray($inputData);
}

Here, we are trading performance (the cost of a function call) for both developer efficiency and reduced future maintenance costs. In general, the trade-off is worth it; most PHP developers work on small sites where developers are more expensive than runtime costs (within reason). The time saved from proving that code is working (and bailing immediately we prove otherwise) is worth saving.

We're also introducing an important principle: there's no return value to check. If execution continues on the line below the call to constraint_mustBeArray(), we can assume that the constraint was passed. If the constraint failed, we let whatever exception handlers there are, well, handle it.

There's a couple of problems with this style that have been nagging me. It h

Truncated by Planet PHP, read more at the original (another 7653 bytes)