Re: DbC for PHP?
| From: | Alexander Lisachenko | Date: | Tue, 28 Jan 2014 11:05:11 +0000 |
| Subject: | Re: DbC for PHP? | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-71665@lists.php.net to get a copy of this message | ||
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 <krebs.seb@gmail.com>
> 2014-01-28 Yasuo Ohgaki <yohgaki@ohgaki.net>
>
> > 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°V
> À¼J7u›(jÛ¥ðU
> > :
> >
> > 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
>