Hello, internals!

>From my point of view, contracts should not affect execution of source code
in production env, or can be enabled partially. I have implemented DbC
paradigm on top of the AOP layer, so each contract can be defined via
annotation and looks pretty nice, for example :

use PhpDeal\Annotation as Contract;

/**
 * Simple trade account class
 * @Contract\Invariant("$this->balance > 0")
 */
class Account implements AccountContract
{

    /**
     * Current balance
     *
     * @var float
     */
    protected $balance = 0.0;

    /**
     * Deposits fixed amount of money to the account
     *
     * @param float $amount
     *
     * @Contract\Verify("$amount>0 && is_numeric($amount)")
     * @Contract\Ensure("$this->balance == $__old->balance+$amount")
     */
    public function deposit($amount)
    {
        $this->balance += $amount;
    }

    /**
     * Returns current balance
     *
     * @Contract\Ensure("$__result == $this->balance")
     * @return float
     */
    public function getBalance()
    {
        return $this->balance;
    }
}

All contracts (verify|ensure) are enforced only when DbC is enabled and
doesn't have an impact on execution for production mode. Moreover, all
annotations are parsed only once, decorators are generated too, so overhead
is minimal even for debug mode. Engine takes care to insert appropriate
before/around checks via an aspect
https://github.com/lisachenko/php-deal/blob/master/src/PhpDeal/Aspect/ContractCheckerAspect.php

Here is a simple snippet of pointcut definition and advice body:

    /**
     * Verifies pre-condition contract for the method
     *
     * @param MethodInvocation $invocation
     * @Before("@annotation(PhpDeal\Annotation\Verify)")
     *
     * @throws ContractViolation
     */
    public function preConditionContract(MethodInvocation $invocation)
    {
        $object = $invocation->getThis();
        $args   = $this->getMethodArguments($invocation);
        $scope  = $invocation->getMethod()->getDeclaringClass()->name;

        foreach ($invocation->getMethod()->getAnnotations() as $annotation) {
            if (!$annotation instanceof Contract\Verify) {
                continue;
            }

            if (!$this->isContractSatisfied($object, $scope, $args,
$annotation)) {
                throw new ContractViolation($invocation, $annotation->value);
            };
        }
    }





2015-02-05 15:13 GMT+03:00 Patrick Schaaf <p...@bof.de>:

> On Thursday 05 February 2015 15:14:04 Dmitry Stogov wrote:
> >
> > function foo()
> >     requre(<input-assert-expression>)
> >     ensure(<output-assert-expression>)
> > {
> >   ...
> > }
> >
> > It would require only one new reserved word "ensure".
>
> Regarding syntax.... This could be another place where the irrationally-
> dreaded declare would make sense:
>
> function foo() {
>     declare(pre) {
>       if (whatever...) return false;
>       // arbitrary PHP code
>     }
>     declare(post=$resultvar) {
>       if ($resultvar == XXX) return true;
>       return false;
>     }
> }
>
> This way, no new reserved words are needed at all, and the programmer can
> give
> a name to the "variable that holds the result" locally to avoid clashes
> with
> anything else in the function.
>
> I'm a bit undecided whether returning true/false there to give the verdict,
> would be the best way. Maybe better would be another use for declare,
> without
> a block, to declare that the pre/postcondition failed - giving a nice
> place to
> put a suitable message, too. And again without introducing any extra
> keywords:
>
> function foo() {
>     declare(post=$resultvar) {
>         if ($resultvar == XXX) declare(fail="My $resultvar looks fishy");
>     }
> }
>
> best regards
>   Patrick
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>

Reply via email to