Search code examples
phpdesign-patternsdatacontract

Is this the right way of implementing "Design by contract" pattern in PHP?


I've discovered the "Design by contract" pattern and how to implement in in PHP. I can't find a real world example of how to do this in PHP. First question is am i'm doing it in the right way? Second one is why the assert callback is not honored?

A static class Asserts for reusable assertions:

class Asserts
{
    public static function absentOrNotNumeric($value)
    {
        return !isset($value) ? true : is_numeric($value);
    }
}

Usage:

assert_options(ASSERT_ACTIVE,   true);
assert_options(ASSERT_BAIL,     true);
assert_options(ASSERT_WARNING,  true);
assert_options(ASSERT_CALLBACK, array('UseAsserts', 'onAssertFailure'));

class UseAsserts
{
    private $value;

    public function __construct($value)
    {
        // Single quotes are needed otherwise you'll get a
        // Parse error: syntax error, unexpected T_STRING 
        assert('Asserts::absentOrNotNumeric($value)');
        $this->value = $value;
    }

    public static function onAssertFailure($file, $line, $message)
    {
        throw new Exception($message);
    }
}

// This will trigger a warning and stops execution, but Exception is not thrown
$fail = new UseAsserts('Should fail.');

Only the (right) warning is triggered:

Warning: assert() [function.assert]: Assertion "Asserts::absetOrNotNumeric($value)" failed.


Solution

  • Your exception is being thrown, altering it to:

    public static function onAssertFailure($file, $line, $message)
    {
        echo "<hr>Assertion Failed:
        File '$file'<br />
        Line '$line'<br />
        Code '$code'<br /><hr />";
    }
    

    results in a display of the text, some testing discovers that if you alter this option

    assert_options(ASSERT_BAIL,     false);
    

    The exception will be thrown, so it seems that it bails on the execution prior to throwing the exception.

    Hope that helps