Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:81914 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 68198 invoked from network); 5 Feb 2015 12:32:27 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 5 Feb 2015 12:32:27 -0000 Authentication-Results: pb1.pair.com header.from=dmitry@zend.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=dmitry@zend.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 209.85.220.172 as permitted sender) X-PHP-List-Original-Sender: dmitry@zend.com X-Host-Fingerprint: 209.85.220.172 mail-vc0-f172.google.com Received: from [209.85.220.172] ([209.85.220.172:36164] helo=mail-vc0-f172.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id E3/28-27691-AD263D45 for ; Thu, 05 Feb 2015 07:32:26 -0500 Received: by mail-vc0-f172.google.com with SMTP id le20so2579913vcb.3 for ; Thu, 05 Feb 2015 04:32:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=abLpbGUtUvuTfwi2SxCguOYEWJDZzkYebl8DXW/xhOo=; b=do8ywuZU4bN7RkNu3oTy1gdWtb/dFGEDxCf8hITOvlXGHqzqIyddIuQdiLGwb5fWVL weqUcnEHdPDO1fgES2BJEqiaQ1zbJIo1LJUP3IwznigS7ph9YybTwfo93Wpu9YayU8jM xnKri55q2kp1HXWKdqGe95haiH4Uc2Q30lv57K4srtAOcRzu7xA+dkYaOagTCVfclXEn QvjNU6wbrY7i1hmB8PnZophcxApd4R5QdjhxUYQGUaOWRW1I+sUncA1Ib3dhDWTleTAC M7ymNfpox+aG6mG+Cr/1feyAffp/tzpKvUQPapGP3f2LLjgZN3jdgkiX/TeJ+gWgw86t eEOQ== X-Gm-Message-State: ALoCoQk8+bR9dNDe/xDJ+QlHk+pe4JkTTkqfUkGA3BLo8nw8dbC0/B5kDpp7OguXGhROWfZdUz/lV1K0SU6el/vm91u2xJvBOWRiW9++BubPAJ+M1OZ5261m4IWIEt6/u1D98XGF4on7H6NNgeuWl9VIldTTOhJKiA== MIME-Version: 1.0 X-Received: by 10.52.103.75 with SMTP id fu11mr1605702vdb.5.1423139543005; Thu, 05 Feb 2015 04:32:23 -0800 (PST) Received: by 10.52.74.73 with HTTP; Thu, 5 Feb 2015 04:32:22 -0800 (PST) In-Reply-To: References: <7740874.yAST26hVNS@rofl> Date: Thu, 5 Feb 2015 16:32:22 +0400 Message-ID: To: Alexander Lisachenko Cc: Patrick Schaaf , PHP internals list , Yasuo Ohgaki Content-Type: multipart/alternative; boundary=047d7b86d990ed48a2050e567eff Subject: Re: [PHP-DEV] Design by Contract From: dmitry@zend.com (Dmitry Stogov) --047d7b86d990ed48a2050e567eff Content-Type: text/plain; charset=UTF-8 Hi Alexander, Defining contracts through doc-comments is also possible, but this way is not native. On the other hand, if you already have this implemented, we may just reuse it. Thanks. Dmitry. On Thu, Feb 5, 2015 at 3:24 PM, Alexander Lisachenko < lisachenko.it@gmail.com> wrote: > 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 : > >> On Thursday 05 February 2015 15:14:04 Dmitry Stogov wrote: >> > >> > function foo() >> > requre() >> > ensure() >> > { >> > ... >> > } >> > >> > 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 >> >> > --047d7b86d990ed48a2050e567eff--