PhpRiot
News Archive
PhpRiot Newsletter
Your Email Address:

More information

Getting Started With ContractLib

Note: This article was originally published at Planet PHP on 16 January 2012.
Planet PHP

In my last blog post, I introduced ContractLib, a simple programming by contract library that I've created for PHP 5.3 onwards. And I promised some examples :)

Installing ContractLib

ContractLib is available from the Phix project's PEAR channel. Installing it is as easy as:

$ pear channel-discover pear.phix-project.org $ pear install -a phix/ContractLib

At the time of writing, this will install ContractLib-2.1.0. We use semantic versioning, so these examples will continue to work with all future releases of ContractLib-2.x.

Adding ContractLib To Your Project

Assuming you're using a PSR-0 compatible autoloader, just import the Contract class into your PHP file:

Adding A Pre-condition Contract To Your Method Or Function

Take a trivial method like this:

This method works fine a until someone passes a non-array as the parameter. At that point, your code stops working - not because your code is wrong, but because someone used it in the wrong way. This is a classic cause of buggy PHP apps. Thankfully, it's very easy to address using ContractLib.

If we were certain that the $params parameter was always an array, then we can keep the method itself extremely simple and clean. We can ensure that by adding a pre-condition using ContractLib.

Now, if someone passes in a non-array, the caller will automatically get an E5xx_ContractFailedException, which makes it clear that the fault is in the caller's code a not your's.

PHP 5.4as upcoming support for better type-hinting is another way to catch this kind of error, but not only does ContractLib work today with PHP 5.3 (which means you don't have to wait to migrate to PHP 5.4), but also that you can write tests for anything, not just the checking that's built into PHP.

This means you can make your code much more robust, by tightening up on the quality of the parameter passed into your code by other programmers. To extend our example, we might decide that an empty array is also unacceptable:

0, '$params cannot be an empty array'); }); // original method code continues here $params[] = time(); } }

The point here is that we can go way beyond type-hinting checks (important as they are) and look inside parameters to make sure they are suitable.

Here's a real example from Phix's CommandLineLib:

use Phix_Project\ContractLib\Contract; class CommandLineParser { // ... public function parseSwitches($args, $argIndex, DefinedSwitches $expectedOptions) { // catch programming errors Contract::Preconditions(function() use ($args, $argIndex, $expectedOptions) { Contract::RequiresValue($args, is_array($args), '$args must be array'); Contract::RequiresValue($args, count($args) 0, '$args cannot be an empty array'); Contract::RequiresValue($argIndex, is_integer($argIndex), '$argIndex must be an integer'); Contract::RequiresValue($argIndex, count($args) = $argIndex, '$argIndex cannot be more than +1 beyond the end of $args'); Contract::RequiresValue($expectedOptions, count($expectedOptions-getSwitches()) 0, '$expect

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