So, is it possible to use annotations for defining such metadata on engine-level? This will be a good way to do this and to define custom handlers via AST hooks, that can be able to patch method definition node with concrete opcodes.
2015-02-05 15:24 GMT+03:00 Alexander Lisachenko <lisachenko...@gmail.com>: > 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 >> >> >