Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:81911 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 63362 invoked from network); 5 Feb 2015 12:24:42 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 5 Feb 2015 12:24:42 -0000 Authentication-Results: pb1.pair.com smtp.mail=lisachenko.it@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=lisachenko.it@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.51 as permitted sender) X-PHP-List-Original-Sender: lisachenko.it@gmail.com X-Host-Fingerprint: 74.125.82.51 mail-wg0-f51.google.com Received: from [74.125.82.51] ([74.125.82.51:56390] helo=mail-wg0-f51.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 2E/17-27691-90163D45 for ; Thu, 05 Feb 2015 07:24:41 -0500 Received: by mail-wg0-f51.google.com with SMTP id k14so7233393wgh.10 for ; Thu, 05 Feb 2015 04:24:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=78mmk/s+lHn9VqynTnIDrgGvFOl/MtmNDykRcMeMOFE=; b=Qx1TR4HeqCHJ47EV3wjIRtUUINXQPc2Nn2fz8Z1oYBhGU9CI/Rc9bwyLJB+mggE0E2 YnULujE9Y9Mf49x0XZrniiG9sRShbt4MbLLgnhNfPf8Ap7E0aiWOKFl/hmbZ+GZmkk1/ hu8AkNFfvrSRJNldnjX8fN9gKEAa62U3Zpo5BJzQv1bpF7ZrVyCn7rXasAsr4+zepwsT prF/gESzxBf/MK4YUU3Xy+fU6N8/ODvGQRYhVe6UPfcho3AaODgHd2eRWLm9CJPGkAz0 pv1pRSLZ0iWFC47IGsP7An7YUx51RAyu8WDR8m3lYAS+1Bp492duQZsMN9ikOjnGeMLU VhEA== MIME-Version: 1.0 X-Received: by 10.180.19.228 with SMTP id i4mr14831044wie.13.1423139078456; Thu, 05 Feb 2015 04:24:38 -0800 (PST) Received: by 10.194.154.229 with HTTP; Thu, 5 Feb 2015 04:24:38 -0800 (PST) In-Reply-To: <7740874.yAST26hVNS@rofl> References: <7740874.yAST26hVNS@rofl> Date: Thu, 5 Feb 2015 15:24:38 +0300 Message-ID: To: Patrick Schaaf Cc: PHP internals list , Dmitry Stogov , Yasuo Ohgaki Content-Type: multipart/alternative; boundary=bcaec53d55073ccade050e566352 Subject: Re: [PHP-DEV] Design by Contract From: lisachenko.it@gmail.com (Alexander Lisachenko) --bcaec53d55073ccade050e566352 Content-Type: text/plain; charset=UTF-8 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 > > --bcaec53d55073ccade050e566352--