rfc:dbc2
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:dbc2 [2015/02/10 07:00] – yohgaki | rfc:dbc2 [2015/03/01 03:35] – yohgaki | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Version: 0.1 | * Version: 0.1 | ||
* Date: 2015-02-10 | * Date: 2015-02-10 | ||
- | * Author: Yasuo Ohgaki < | + | * Author: Yasuo Ohgaki < |
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
- | ===== Important Note==== | + | ===== Important Note ===== |
- | This RFC is a part of "Native DbC support" RFC. | + | This RFC is part of "Design by Contract Introduction" RFC |
- | http:// | + | * https:// |
- | There are many way to achieve DbC. This RFC proposes | + | This RFC is an alternative approach to " |
+ | * http://wiki.php.net/ | ||
- | ===== Introduction ===== | + | Contracts can be defined without modification to the language, however, the D documentation calls the resulting implementation " |
- | Design by Contract (DbC) or Contract Programming is powerful program design concept based on **Contracts** that | + | Other advantages of a native implementation, |
- | | + | * a consistent look and feel for the contracts |
- | | + | * tool support |
- | | + | |
+ | | ||
+ | * handling of contract | ||
- | These contracts are evaluated development time only. Therefore, there is **no performance penalty** with DbC. | + | All of the above applies to PHP. |
- | * http:// | + | ===== Introduction ===== |
- | * http:// | + | |
- | ====DbC Changes | + | The D manual contains |
- | ==CalleR and CalleE responsibility and validation: | + | > The idea of a contract is simple - it's just an expression that must evaluate to true. If it does not, the contract |
- | * 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 | + | |
- | ==Exit value validation: | + | This should be easily comprehensible, |
- | * Without | + | |
- | * With native DbC, return value validity is checked as **postcondition**. It does not require scattered assert(). | + | |
- | ==Class state validation:== | + | ===== Proposal ===== |
- | * 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. | + | Support for the following contracts will be introduced: |
- | DbC reverses the responsibility caller and callee, ensures parameters, return | + | * precondition |
+ | * postcondition | ||
+ | * invariant | ||
- | DbC encourages users to control inputs/ | + | ===== Pre and Post Condition ===== |
- | ====Readability of Code / Testing Code==== | + | These contracts should be defined after the function declaration, |
- | Since contracts are written | + | Multiple precondition and postcondition |
- | DbC is __NOT__ | + | < |
+ | function add(int $a, int $b) : int | ||
+ | require($a > 0) | ||
+ | require($b > 0) | ||
+ | return($ret, $ret > 0, " | ||
+ | { | ||
+ | return $a + $b; | ||
+ | } | ||
+ | </code> | ||
+ | this code is going to be evaluated as | ||
- | ====General Concern of Design by Contract==== | + | < |
+ | function add(int $a, int $b) : int | ||
+ | { | ||
+ | assert($a > 0); | ||
+ | assert($b > 0); | ||
+ | $ret = $a + $b; | ||
+ | assert($ret > 0, " | ||
+ | return $ret; | ||
+ | } | ||
+ | </ | ||
- | 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. | + | ===== Invariant ===== |
- | 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" | + | Invariant contracts are declared using **require** inside class body. Multiple invariant contracts may be used. They may access object |
+ | < | ||
+ | class Accumulator { | ||
+ | private $sum = 0; | ||
+ | |||
+ | function add(int $a) | ||
+ | require($a > 0) | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
- | ===== Proposal ===== | + | require($this-> |
+ | } | ||
+ | </ | ||
- | Introduce native contracts " | + | this code is going to be evaluated as |
- | While new usage of require, return may seem strange at first, users can use familiar PHP syntax for DbC definitions. | + | < |
+ | class Accumulator { | ||
+ | private $sum = 0; | ||
+ | |||
+ | function add(int $a) | ||
+ | { | ||
+ | assert($a > 0); | ||
+ | assert($this-> | ||
+ | $this-> | ||
+ | assert($this-> | ||
+ | } | ||
+ | } | ||
+ | </ | ||
- | | + | **Invariant contracts are not evaluated when object properties are changed from outside the class scope.** |
- | | + | |
- | **require**, | + | ====Contracts Inheritance Rules==== |
+ | Contracts are constant, this has the following implications: | ||
- | ====Example==== | + | * a derived |
- | <code php> | + | |
- | class Product { | + | |
- | | + | |
- | require($this-> | + | |
- | // User is supposed to check inventory first | + | Thus, given the following code: |
- | function haveEnoughInventory($quantity) | + | |
- | require($quantity > 0) // Precondition | + | |
- | { | + | |
- | return (bool) ($this-> | + | |
- | } | + | |
- | // Sell inventory | + | < |
- | function sell($quantity) | + | class Child { |
- | require($quantity > 0) // Precondition | + | require ($this->age < 18); |
- | return($> | + | |
- | { | + | public function |
- | return $this> | + | require(somethingAbout($input)) { |
- | } | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | ====Longer Class Definition Example - need better one==== | + | |
- | < | + | |
- | class MySession2 extends SessionHandler | + | |
- | public $path; | + | |
- | require(is_string($this->path)) && !empty($this-> | + | |
- | + | ||
- | public function | + | |
- | require(strlen($path) > 3 && strlen($name) > 3); | + | |
- | return(is_bool($> | + | |
- | | + | |
- | | + | |
- | $path = sys_get_temp_dir(); | + | |
- | } | + | |
- | $this-> | + | |
- | return true; | + | |
} | } | ||
- | | + | |
- | | + | } |
- | { | + | |
- | return true; | + | |
- | | + | |
- | public function read($id) | + | class Monster extends Child { |
- | return(is_string($> | + | |
- | | + | |
- | return @file_get_contents($this->path . $id); | + | |
- | } | + | |
- | public function | + | public function |
- | require(strlen($id) > 10 && strlen($data) > 10) | + | require(somethingElseAbout($input)) { |
- | return(is_bool($> | + | |
- | | + | |
- | | + | |
} | } | ||
- | | + | /* ... */ |
- | require(strlen($id) > 10) | + | |
- | return(is_bool($> | + | |
- | { | + | |
- | @unlink($this-> | + | |
- | } | + | |
- | + | ||
- | public function gc($maxlifetime) | + | |
- | require($maxfiletime > 60) | + | |
- | return($> | + | |
- | { | + | |
- | foreach (glob($this-> | + | |
- | if (filemtime($filename) + $maxlifetime < time()) { | + | |
- | @unlink($filename); | + | |
- | } | + | |
- | } | + | |
- | return true; | + | |
- | } | + | |
} | } | ||
</ | </ | ||
+ | //Monster// must not break **any** contract in //Child//. | ||
====Execution Control==== | ====Execution Control==== | ||
- | Introduce | + | A new " |
- | A method/ | + | * dbc=on |
+ | * dbc=off | ||
+ | * dbc=zero_cost - don't generate code for contracts. This may be set only in php.ini and can't be changed through ini_set(). | ||
- | ===Basic Execution=== | + | The default value is " |
- | require() - executed before function body | + | ===Contracts Execution Order=== |
- | return() - executed upon return | + | |
- | invariant - executed after require() and before return(). There are few exceptions explained later. | + | |
- | ==Development mode: dbc=On == | + | If "dbc" is set to " |
- | - require() | + | - all require() |
- | - class invariant | + | - all require() contracts (invariant) for this class and parents |
- | - method() | + | - method |
- | - class invariant | + | - all require() contracts (invariant) for this class and parents |
- | - return() | + | - all return() |
- | + | ||
- | ==Production mode: dbc=Off == | + | |
- | + | ||
- | - method() | + | |
- | + | ||
- | ==Execution details when DbC is enabled== | + | |
**Invariant and Special Methods** | **Invariant and Special Methods** | ||
- | * < | + | * < |
- | * < | + | * < |
- | + | ||
- | **Class Inheritance** | + | |
- | + | ||
- | * When parent class methods are called, DbC conditions are executed | + | |
- | * Special methods execution exception is the same | + | |
- | + | ||
- | **Abstract Class** | + | |
- | + | ||
- | * The same as usual class. | + | |
- | + | ||
- | **Trait** | + | |
- | + | ||
- | * The same as usual class. | + | |
**Static Call** | **Static Call** | ||
- | * Only pre/post contracts | + | * Only pre and post conditions |
- | + | ||
- | **Interface** | + | |
- | + | ||
- | * Cannot define DbC contracts. | + | |
- | + | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 225: | Line 189: | ||
==== To Opcache ==== | ==== To Opcache ==== | ||
- | + | Opcache will have to be extended to support contracts and store them in shared memory. | |
- | Dmitry, could you write impact when discussion is finished? | + | |
==== New Constants ==== | ==== New Constants ==== | ||
Line 233: | Line 195: | ||
==== php.ini Defaults ==== | ==== php.ini Defaults ==== | ||
- | |||
dbc=Off for all (INI_ALL) | dbc=Off for all (INI_ALL) | ||
Line 241: | Line 202: | ||
===== Open Issues ===== | ===== Open Issues ===== | ||
+ | * Contracts inheritance rules | ||
+ | * Consider introduction of **static require()** as class invariant for static methods | ||
* Need to discuss syntax | * Need to discuss syntax | ||
* How to manage votes for 2 RFCs | * How to manage votes for 2 RFCs | ||
- | |||
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== |
rfc/dbc2.txt · Last modified: 2018/03/01 23:19 by carusogabriel