Inspection

Since v1.2016062801

Description

Inspection is an interface. It defines the ::apply()->to() pattern used by both Assurance and Requirement classes.

Public Interface

Inspection has the following public interface:

// Inspection lives in this namespace
namespace GanbaroDigital\Defensive\V1\Interfaces;

interface Inspection
{
    /**
     * throws exception if our inspection fails
     *
     * @param  mixed $fieldOrVar
     *         the data to be examined
     * @param  string $fieldOrVarName
     *         what is the name of $fieldOrVar in the calling code?
     * @return void
     */
    public function __invoke($fieldOrVar, $fieldOrVarName = "value");

    /**
     * throws exception if our inspection fails
     *
     * this is an alias of to() for readability purposes
     *
     * @param  mixed $fieldOrVar
     *         the data to be examined
     * @param  string $fieldOrVarName
     *         what is the name of $fieldOrVar in the calling code?
     * @return void
     */
    public function inspect($fieldOrVar, $fieldOrVarName = "value");

    /**
     * throws exception if our inspection fails
     *
     * @param  mixed $fieldOrVar
     *         the data to be examined
     * @param  string $fieldOrVarName
     *         what is the name of $fieldOrVar in the calling code?
     * @return void
     */
    public function to($fieldOrVar, $fieldOrVarName = "value");
}

How To Use

A Base Interface

Inspection is a base interface. Its purpose is to define common functionality.

Assurance and Requirement are both interfaces that extend Inspection.

The Apply->To Pattern

All inspections follow the ::apply()->to() pattern:

function foo($args)
{
    // robustness!
    RequireListOfFish::apply()->to($args, '$args');

    // ... do some work

    // all done
    EnsureInRange::apply(100, 200)->to($retval, '$retval');
    return $retval;
}

Here's how the pattern works:

The benefits of this pattern include:

The downside of the pattern is that each inspection takes a minimum of three method calls:

  1. Your code calls ::apply()
  2. Internally, ::apply() creates a new object and calls its ::__construct()
  3. Your code calls ::to() on the created object

It's our experience - and our thesis - that the time it takes a developer to write and ship working code is now the biggest bottleneck on projects. Some of this cost is writing the code the first time, and some of this cost is going back and debugging the code and fixing errors only discovered by your customers.

Adding strict error detection to code (in the form of inspections) helps you ship code that works first time. Reducing post-release maintenance and support frees up more time to spend on writing new code.

In PHP 7.0 onwards, method calls aren't the major overhead that they used to be, which helps a lot. Plus, you can take advantage of the new behaviour of assert() in PHP 7.0 to switch off all inspections in your code if you need to:

// only works in PHP 7.0 and up
//
// set assert.active=0 in php.ini to disable all assert() calls
assert(EnsureInRange::apply(100,200)->to($retval));

Inspection Adapters

You can use all implementations of Inspection as inspection adapters:

$assurances = [
    new EnsureString(),
    new EnsureMinLength(100)
];
foreach ($assurances as $assurance) {
    // invokeable object
    $assurance($data, '$data');

    // for readability, this works too
    $assurance->inspect($data, '$data');
}

Here's how this pattern works:

Notes

None at this time.

Changelog

v1.2016081301