Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Created February 17, 2015 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ircmaxell/292aa7e31e093c0efb06 to your computer and use it in GitHub Desktop.
Save ircmaxell/292aa7e31e093c0efb06 to your computer and use it in GitHub Desktop.
<?php
trait VerifyPrecondition {
protected $parent;
protected function verifyPrecondition($method, array $args) {
$objs = [new ReflectionMethod($this->parent, $method)];
foreach ((new ReflectionObject($this->parent))->getInterfaces() as $iface) {
if ($iface->hasMethod($method)) {
$objs[] = $iface;
}
$parent = $objs[0]->getDeclaringClass()->getParentClass();
while ($parent) {
if ($parent->hasMethod($method)) {
$rm = $parent->getMethod($method);
$objs[] = $rm;
$parent = $rm->getDeclaringClass()->getParentClass();
} else {
$parent = false;
}
}
while ($r = array_shift($objs)) {
$r = new ReflectionMethod($obj, $method);
$scope = [];
foreach ($r->getParameters() as $arg) {
// add additional checks here
$scope[$arg->getName()] = isset($args[$arg->getPosition()]) ? $args[$arg->getPosition()] : $arg->getDefaultValue();
}
foreach ($r->getAnnotations("precondition") as $annotation) {
if (!$annotation->getValue($scope, $this->parent)) {
throw new ConstraintViolationException(...);
}
}
}
}
}
interface Foo {
<precondition($a > 0)>
<precondition($div > 0)>
public function getRemainder(int $a, int $div): int;
}
class FooImpl implements Foo{
public function getRemainder(int $a, int $div): int {
return $a % $div;
}
}
class FooImpl2 implements Foo {
<precondition($a != $div)>
public function getRemainder(int $a, int $div): int {
return $a % $div;
}
}
class PreconditionVerifierForFoo implements Foo {
use VerifyPrecondition;
public function __construct(Foo $foo) {
$this->parent = $foo;
}
public function getRemainder(int $a, int $div): int {
$this->verifyPreconditions(__METHOD__, func_get_args());
return $this->parent->getRemainder($a, $div);
}
}
$foo = new FooImpl;
$foo->getRemainder(5, 0); // 0
$verifiedFoo = new PreconditionVerifierForFoo($foo);
$verifiedFoo->getRemainder(5, 5); // 0
$verifiedFoo->getRemainder(5, 0); // ConstraintViolationException
$verifiedFoo2 = new PreconditionVerifierForFoo(new Foo2);
$verifiedFoo2->getRemainder(5, 5); // ConstraintViolationException
<?php
class ReflectionAnnotation {
/**
* Get the name of the annotation
*/
public function getName(): string {}
/**
* Executes the expression using the supplied scope and object context
*/
public function getValue(array $scope = [], object $context = null): mixed {}
/**
* Get the raw AST in array form
*/
public function getAst(): array {}
}
$r = new ReflectionMethod($obj, $method);
$annotations = $r->getAnnotations(); // return all
$annotations = $r->getAnnotations($name); // return all named $name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment