Home
Name Modified Size InfoDownloads / Week
LICENCE 2012-04-06 31.8 kB
Contract-v1.0.zip 2012-04-04 32.0 kB
README 2012-04-04 6.6 kB
Totals: 3 Items   70.5 kB 0
PHP Design by Contract v1.0

Copyright (c) 2012 James Watts (SOLFENIX)
http://www.solfenix.com

This is FREE software, licensed under the GNU/GPL
http://www.gnu.org/licenses/gpl.html


PHP Design by Contract provides a basic implementation of contract 
programming for PHP 5.3+ with namespaces.

The base Contract class allows new or existing classes to define 
properties as protected Attributes and methods as Routines, which 
require argument type/class validation, aswell as PreCondition and 
PostCondition checks. Instances can also test for state consistency 
with an invariant check.


To use the package it's highly recommended to use a PSR-0 compatible 
autoloader for required classes.

You can find a fully compatible autoloader here: https://sourceforge.net/p/php-autoload

Once you've unpacked the files into your include path the package is 
ready for use.


To use the base Contract class simply extend it with a new or 
existing class, for example:


 class Person extends Contract {
 
     // class members are defined here
 }


When extending the Contract class certain magic methods become 
available. The first of these methods is __create( void ). This 
method behaves as a constructor function for the instance object.


 public function __create()
 {
     // object is defined here
 }


To define the Attributes (properties) and Routines (methods) 
available for this object there are 2 additional magic methods, 
__attribute( Attribute $attribute ) and __routine( Routine $routine ).

The Attribute class defines a property for the object, using 
setName( string $name ) for the name of the property, 
setType( int $type ) for the data type stored in the property, 
and setValue( mixed $value ) for the default value of the property, 
for example:


 $attribute = new Attribute();
 $attribute->setName( 'example' );
 $attribute->setType( DataTypes::TYPE_STRING );
 $attribute->setValue( 'Hello World' );
    

Only the routine of the same object can modify an attribute. If a 
routine of another object attempts to modify an attribute an 
IllegalAttributeAccessException will be thrown. Additionally, if the 
data type of the value being set to the attribute is not the same as 
the type defined by the attribute an InvalidAttributeTypeException 
will be thrown.

Once the attribute has been defined it can be registered on the 
object.


 $this->__attribute( $attribute );


The DataTypes class defines the data types available as the following 
constants:

- TYPE_NULL: A discriminated null value
- TYPE_BOOLEAN: A boolean logical value
- TYPE_NUMERIC: A valid numeric value
- TYPE_INTEGER: A whole number
- TYPE_DOUBLE: A double precision floating point number
- TYPE_STRING: A string of characters
- TYPE_ARRAY: An array of values (keys permitted)
- TYPE_OBJECT: An object
- TYPE_LAMBDA: An instance of Closure
- TYPE_RESOURCE: An external PHP resource

A routine can be either a procedure or a function. The difference 
between these types is that a procedure is used to modify the state 
of an object, but does not return a value, whilst a function is used 
to access the object and return a value, but not modify it's state. 
This concept is called "command/query spearation".

The Routine class defines a method for the object, using 
setName( string $name ) for the name of the method, 
setType( int $type ) for the type of the routine, 
setArguments( array $arguments ) for the validation of the data 
types of the arguments expected and recieved by the method, and 
setHandler( callable $callback ) for the callback to execute when 
called, for example:


 $routine = new Routine();
 $routine->setName( 'test' );
 $routine->setType( Routine::TYPE_PROCEDURE );
 $routine->setArguments( array(
     DataTypes::TYPE_NULL,
     DataTypes::TYPE_BOOLEAN,
     DataTypes::TYPE_NUMERIC,
     DataTypes::TYPE_INTEGER,
     DataTypes::TYPE_DOUBLE,
     DataTypes::TYPE_STRING,
     DataTypes::TYPE_ARRAY,
     DataTypes::TYPE_OBJECT,
     DataTypes::TYPE_LAMBDA,
     DataTypes::TYPE_RESOURCE,
     'Test\MyContract'
 ) );
 $routine->setHandler( array( $this, 'testRoutine' ) );


If an argument is passed to the routine but is not of the data type 
specified by the routine in the arguments array, an 
InvalidArgumentTypeException will be thrown. Also, if a number of 
arguments is passed to the routine which is less than the number 
expected by the routine, defined by the length of the arguments 
array, a MissingRequiredArgumentsException will be thrown.

The callback for a routine can be any value considered by PHP as 
callable. The callback for the Routine receives the arguments passed 
to the method.

A routine can also optionally define a PreCondition and a 
PostCondition. These are executed before and after the routine's 
callback. These validators use setHandler( callable $callback ) for 
the callback to execute when called, which should return a boolean 
value. In the case when "false" is returned by the PreCondition 
callback the routine will not execute, and a PreConditionException 
will be thrown. And in the case when "false" is returned by the 
PostCondition callback, the object will be returned to it's last 
state before the execution of the routine, and a 
PostConditionException will be thrown.


 $preCondition = new PreCondition();
 $preCondition->setHandler( function( $object, $arguments ) {
     return true;
 } );
 
 $postCondition = new PostCondition();
 $postCondition->setHandler( array( $this, 'testPostCondition' ) );
 
 $routine->setPreCondition( $preCondition );
 $routine->setPostCondition( $postCondition );


The callbacks for a conditions can be any value considered by PHP as 
callable. The callback for the PreCondition receives 2 arguments, the 
object and the arguments passed to the routine, whilst the callback 
for the PostCondition callback also receives 2 arguments, except the 
second argument is the return value of the routine.

Once the routine has been defined it can be registered on the object.


 $this->__routine( $routine );


Finally, the Contract class provides an __invariant( void ) magic 
method. This method is called internally after every routine 
execution. The purpose of this method is to ensure the object is in 
a coherent state, and has not been corrupted.


 public function __invariant()
 {
     // check object state
 }


This method should return a boolean value. In the case when "false" 
is returned, the object will be returned to it's last state before 
the execution of the routine, and an InvariantException will be 
thrown.

All exceptions related to the PHP Design by Contract package extend 
the ContractException class.

Source: README, updated 2012-04-04