rfc:dbc2

This is an old revision of the document!


PHP RFC: Native DbC support as definition

Important Note

This RFC is a part of “Native DbC support” RFC. http://wiki.php.net/rfc/dbc

There are many way to achieve DbC. This RFC proposes DbC as function/method definition.

Introduction

Design by Contract (DbC) or Contract Programming is powerful program design concept based on Contracts that

  1. Define precondition contract for methods/functions. i.e. Define Parameter value specifications/conditions.
  2. Define postcondition contract for methods/functions. i.e. Define Return value specifications/conditions.
  3. Define invariant contract for methods/functions. i.e. Define class state must be true always.

These contracts are evaluated development time only. Therefore, there is no performance penalty with DbC.

DbC Changes the Way Program is Designed/Developed/Tested

CalleR and CalleE responsibility and validation:
  • With modularized design without DbC, the more code is consolidated, the better code is.
    Therefore, parameter validity is checked deep into the code. Parameter validity check is calleE responsibility.
  • With DbC, parameter checks are done as precondition. Passing valid parameter to a function is calleR responsibility.
Exit value validation:
  • Without native DbC, return value validity cannot be checked without scattered assert() for every place function is used.
    i.e. Programmers has to write “$ret = func(); assert($ret > 0);” everywhere func() is used or func() must have assert() for every return.
  • With native DbC, return value validity is checked as postcondition. It does not require scattered assert().
Class state validation:
  • With native DbC, invariant condition may be defined. Invariant allows programmers consolidate class state which must be TRUE for always.
    e.g. $account_balance >= 0

precondition check can be done with assert(), but other feature requires native DbC.

DbC reverses the responsibility caller and callee, ensures parameters, return value and class state validity without performance penalty. This helps PHP to achieve more efficient development by contract errors, faster execution for production.

With proper use of DbC concept, it is known programs to be more robust, secure and faster. Languages designed lately have native DbC support. e.g. D language. Almost all languages have some kind of DbC supports today.

Readability of Code / Testing Code

Since contracts are written in function/method definition, it's much easier to find function/method spec compared to conditions written in UnitTests. It also enables contract check for running applications operated by humans.

DbC is NOT a complement of UnitTest, but it provide additional way of testing programs. Programs should be tested with and without DbC support by UnitTest. With this procedure, UnitTest condition coverage is improved.

General Concern of Design by Contract

Some may concern that lack of checks under production environment. However, all inputs to programs should validate input parameter validity right after input parameters are passed to program.

This is basic principle of secure programs. Users should not DbC everywhere. User should have proper defense in depth as security measure. Security standard like “ISO 27000” or security guideline like “SANS TOP 25 Monster Mitigations” suggests to have proper output controls, as well as input controls. This applies with or without DbC. DbC encourages proper input/output controls compare to program design without DbC.

Proposal

Introduce native contracts “require”( precondition ), “return”( postcondition ) definition to function/method and special “__invaliant()” method to class.

While new usage of require, return may seem strange at first, users can use familiar PHP syntax for DbC definitions.

  • require(assert-expr [,'Error msg']);
  • return(assert-expr [,'Error msg']);
  • __invaliant() method - it is called only when DbC is enabled

require, return behave just like assert().

Example without **invariant**

class Product {
  protected $inventory;
 
  // User is supposed to check inventory first
  function haveEnoughInventory($quantity) 
    require($quantity > 0)
  {
    return (bool) ($this->inventory - $quantity) >= 0;
  }
 
  // Sell inventory
  function sell($quantity) 
    require($quantity > 0)
    return($ret >= 0) // We have to think of how to specify $ret. Use block? return($ret) {assert($ret >= 0);} as Dmitry suggested.
  {
    return $this>amount - $quantity;
  }
}

Example with **invariant**

class Product {
  protected $inventory;
 
  // Invariants must be TRUE for this class always  - $inventory should not be negative
  function __invariant() {
    assert($this->inventory >= 0);
  }
 
  // User is supposed to check inventory first
  function haveEnoughInventory($quantity) 
    require($quantity > 0)
  {
    return (bool) ($this->inventory - $quantity) >= 0;
  }
 
  // Sell inventory
  function sell($quantity) 
    require($quantity > 0)
  {
    return $this>amount - $quantity;
  }
}

Execution Control

Introduce “dbc” INI switch, Off by default. No additional CLI option for DbC.

A method/function is executed as follows

Development mode: dbc=On

  1. require() conditions
  2. invariant() - method() - invariant()
  3. return() conditions

Production mode: dbc=Off

  1. method()

Backward Incompatible Changes

None

  • No additional keyword
  • __invariant() is a reserved method name

Proposed PHP Version(s)

  • PHP7

RFC Impact

To SAPIs

None

To Existing Extensions

None

To Opcache

Dmitry, could you write impact when discussion is finished?

New Constants

None

php.ini Defaults

dbc=Off for all

  • hardcoded default values
  • php.ini-development values
  • php.ini-production values

Open Issues

  • Need to discuss syntax
  • How to manage votes for 2 RFCs

Unaffected PHP Functionality

This RFC does not affect any existing features

Future Scope

Documentation systems may adopt native DbC syntax for documentation purpose.

Vote

This project requires a 2/3 majority

  • Option would be YES/NO only

Patches and Tests

Links to any external patches and tests go here.

If there is no patch, make it clear who will create a patch, or whether a volunteer to help with implementation is needed.

Make it clear if the patch is intended to be the final patch, or is just a prototype.

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged to
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature

References

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/dbc2.1423523063.txt.gz · Last modified: 2017/09/22 13:28 (external edit)