Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:71665 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 79214 invoked from network); 28 Jan 2014 11:05:15 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 28 Jan 2014 11:05:15 -0000 Authentication-Results: pb1.pair.com header.from=lisachenko.it@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=lisachenko.it@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.47 as permitted sender) X-PHP-List-Original-Sender: lisachenko.it@gmail.com X-Host-Fingerprint: 74.125.82.47 mail-wg0-f47.google.com Received: from [74.125.82.47] ([74.125.82.47:55978] helo=mail-wg0-f47.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 76/EB-01140-9EE87E25 for ; Tue, 28 Jan 2014 06:05:14 -0500 Received: by mail-wg0-f47.google.com with SMTP id m15so466671wgh.14 for ; Tue, 28 Jan 2014 03:05:11 -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=Bgy0u4V+21YviN2cN62CH+tAKmuqQKGd1o7IwH8veZQ=; b=EFNx+krbp34qo9KVJQm3ia4J0JnalcSIBKo0ZXERhyDEHoTtIe0XVu3KyaAooINwUQ 4YbB+Q/HC83YYbIs4zF98vNMPJjRbVgkg9DPE5CCnEsZv0BzeIpbGJKdBtSAUkGG1/Jd +VJpEno+CaC5glEJRJ3OyEIuyvuwgd2KkYZ8WMfmZEvYCdSUquS03Sl5AzFnuyMtucNt Z15TNbVJbKs3w1ykg58ec5oEjf5S1+0eoYkCbLyWp+SLfCWaUAE16UdQ4OCDPjfE4Rr9 BHyBc+MvQkzL9rGN1kihhCaKXlXnpatfpLY2ACx7zzMhnhy0MUHdne3Cp8U2drlsoAVc Gqkw== MIME-Version: 1.0 X-Received: by 10.194.58.132 with SMTP id r4mr626899wjq.45.1390907111346; Tue, 28 Jan 2014 03:05:11 -0800 (PST) Received: by 10.194.48.81 with HTTP; Tue, 28 Jan 2014 03:05:11 -0800 (PST) In-Reply-To: References: Date: Tue, 28 Jan 2014 15:05:11 +0400 Message-ID: To: Yasuo Ohgaki Cc: "internals@lists.php.net" Content-Type: multipart/alternative; boundary=047d7b86dbd849970b04f105cc8c Subject: Re: [PHP-DEV] DbC for PHP? From: lisachenko.it@gmail.com (Alexander Lisachenko) --047d7b86dbd849970b04f105cc8c Content-Type: text/plain; charset=UTF-8 Hello! Design by Contract can be achieved with Aspect-Oriented technology, as it provides set of hooks, such as before method execution, after method execution, around method execution, etc. Logic of contract can be easily defined as an aspect - class that will receive a control before or after method execution to check the contract. For example, we can introduce an annotation as a contract for method and just verify (eval) this contract during method execution. Here is my one-minute implementation with Go! AOP framework. First step is to define an empty Contract annotation: use Doctrine\Common\Annotations\Annotation; /** * @Annotation * @Target("METHOD") */ class Contract extends Annotation { } Next step is to create an aspect, that will be called before each method that has "Contract" annotation: class ContractAspect implements Aspect { /** * Verify a contract for a methods annotated with Contract annotation * * @param MethodInvocation $invocation * @Before("@annotation(Annotation\Contract)") */ public function beforeContract(MethodInvocation $invocation) { $__parameters = $invocation->getMethod()->getParameters(); $__argumentNames = array_map(function (\ReflectionParameter $parameter) { return $parameter->name; }, $__parameters); $__parameters = array_combine($__argumentNames, $invocation->getArguments()); extract($__parameters, EXTR_SKIP); $contract = $invocation->getMethod()->getAnnotation(Contract::class); $result = eval("return {$contract->value}; ?>"); if (!$result) { $obj = $invocation->getThis(); $objName = is_object($obj) ? get_class($obj) : $obj; $methodName = $invocation->getMethod()->name; throw new \LogicException("Contract {$contract->value} violated for {$objName}->{$methodName}"); } } } And now it's possible to use this annotation anywhere to define a contract for method: use Annotation\Contract; class Test { /** * @Contract("strlen($foo) > 6") */ public function bar($foo) { echo $foo; } } // test.php $foo = new Test; $foo->bar('1234567'); // no error $foo->bar('12'); // LogicException: Contract strlen($foo) > 6 violated for Test->bar; What do you think about such implementation of contracts? Feedback is appreciated. 2014-01-28 Sebastian Krebs > 2014-01-28 Yasuo Ohgaki > > > Hi all, > > > > I'm wandering if we could have DbC (Design by Contract) for PHP 6. > > http://en.wikipedia.org/wiki/Design_by_contract > > > > There is user land implementation already. > > > > > https://gitorious.org/higher-order-php/php-contracts/source/5b0a53b9732f0e4dbe79345212c84c74526def3b > > : > > > > It could be done with dbc mode INI switch as follows. > > > > When dbc=on, automatically includes > > > > include __dbc_ . __SCRIPT_NAME__; > > > > when a script is loaded. No error if there is not the script. > > When function/method is called > > > > __dbc_pre_. __FUNCTION__() is called before calling function(). > > __dbc_post_.___FUNCTION__() is called after function() call. > > > > No error if there is not the function. > > > > Couldn't you achieve the same with assert()? > > > > > > Class methods would be more complex, but basic idea is the same. > > Issue would be what we should do with $this with class methods. > > > > Automatic namespace might be nice to have for both function and class. > > > > When dbc=off, these would be skipped at all. > > > > It does not sacrifice performance at all for production while it could > > catch > > various errors during development. It could do more complex assertion > > than assert() and it could check post condition that is difficult to > > achieve > > by assert(). User could have their own strong type safety as long as they > > have strict input validation. It could be used as complement of > annotation. > > > > Just an idea. > > Any comments? > > > > Regards, > > > > -- > > Yasuo Ohgaki > > yohgaki@ohgaki.net > > > > > > -- > github.com/KingCrunch > --047d7b86dbd849970b04f105cc8c--