<?php
class DomainValidator {
const DOMAIN_TAG = '@domain';
private $object;
public function __construct($object) {
$this->object = $object;
}
public function __call($function, $arguments) {
if (!$this->verify_domain($function, $arguments)) {
throw new \DomainException('Bad domain!');
}
array($this->object, $function), $arguments
);
}
public function __get($name) {
return $this->object->name;
}
public function __set($name, $value) {
$this->object->name = $value;
}
private function verify_domain($function, $arguments) {
// Get reference to method
$method = new \ReflectionMethod($this->object, $function);
$domains = $this->get_domains($method->getDocComment());
$arguments = $this->parse_arguments(
$method->getParameters(),
$arguments
);
foreach ($domains as $domain) {
$domain['name'],
$arguments[$domain['parameter']]
)) {
return false;
}
}
return true;
}
private function get_domains($doc_block) {
$lines = explode("\n", $doc_block); $domain_tag = DomainValidator::DOMAIN_TAG . ' ';
foreach ($lines as $line) {
$has_domain = stristr($line, $domain_tag) !== false; if ($has_domain) {
$domain_info = explode($domain_tag, $line); $domain_info = explode(' ', $domain_info[1]); 'name' => $domain_info[0],
'parameter' => $domain_info[1],
);
}
}
return $domains;
}
private function parse_arguments($parameters, $values) {
for ($i = 0, $size = sizeof($values); $i < $size; $i++) { $ret[$parameters[$i]->name] = $values[$i];
}
return $ret;
}
}
class FooDomain {
public static function is_not_empty($input) {
}
}
class Foo {
/**
* @domain FooDomain::is_not_empty my_string
*/
public function print_string($my_string) {
echo $my_string . PHP_EOL;
}
}
$foo = new DomainValidator(new Foo());
$foo->print_string('Hello, world!');
try {
$foo->print_string(''); // throws a DomainException
} catch (\DomainException $e) {
echo 'Could not print an empty string...' . PHP_EOL;
}
PD9waHAKY2xhc3MgRG9tYWluVmFsaWRhdG9yIHsKICAgIGNvbnN0IERPTUFJTl9UQUcgPSAnQGRvbWFpbic7CgogICAgcHJpdmF0ZSAkb2JqZWN0OwoKICAgIHB1YmxpYyBmdW5jdGlvbiBfX2NvbnN0cnVjdCgkb2JqZWN0KSB7CiAgICAgICAgJHRoaXMtPm9iamVjdCA9ICRvYmplY3Q7CiAgICB9CgogICAgcHVibGljIGZ1bmN0aW9uIF9fY2FsbCgkZnVuY3Rpb24sICRhcmd1bWVudHMpIHsKICAgICAgICBpZiAoISR0aGlzLT52ZXJpZnlfZG9tYWluKCRmdW5jdGlvbiwgJGFyZ3VtZW50cykpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IFxEb21haW5FeGNlcHRpb24oJ0JhZCBkb21haW4hJyk7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gY2FsbF91c2VyX2Z1bmNfYXJyYXkoCiAgICAgICAgICAgIGFycmF5KCR0aGlzLT5vYmplY3QsICRmdW5jdGlvbiksCiAgICAgICAgICAgICRhcmd1bWVudHMKICAgICAgICApOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiBfX2dldCgkbmFtZSkgewogICAgICAgIHJldHVybiAkdGhpcy0+b2JqZWN0LT5uYW1lOwogICAgfQoKICAgIHB1YmxpYyBmdW5jdGlvbiBfX3NldCgkbmFtZSwgJHZhbHVlKSB7CiAgICAgICAgJHRoaXMtPm9iamVjdC0+bmFtZSA9ICR2YWx1ZTsKICAgIH0KCiAgICBwcml2YXRlIGZ1bmN0aW9uIHZlcmlmeV9kb21haW4oJGZ1bmN0aW9uLCAkYXJndW1lbnRzKSB7CiAgICAgICAgLy8gR2V0IHJlZmVyZW5jZSB0byBtZXRob2QKICAgICAgICAkbWV0aG9kID0gbmV3IFxSZWZsZWN0aW9uTWV0aG9kKCR0aGlzLT5vYmplY3QsICRmdW5jdGlvbik7CiAgICAgICAgJGRvbWFpbnMgPSAkdGhpcy0+Z2V0X2RvbWFpbnMoJG1ldGhvZC0+Z2V0RG9jQ29tbWVudCgpKTsKICAgICAgICAkYXJndW1lbnRzID0gJHRoaXMtPnBhcnNlX2FyZ3VtZW50cygKICAgICAgICAgICAgJG1ldGhvZC0+Z2V0UGFyYW1ldGVycygpLAogICAgICAgICAgICAkYXJndW1lbnRzCiAgICAgICAgKTsKICAgICAgICBmb3JlYWNoICgkZG9tYWlucyBhcyAkZG9tYWluKSB7CiAgICAgICAgICAgIGlmICghY2FsbF91c2VyX2Z1bmMoCiAgICAgICAgICAgICAgICAkZG9tYWluWyduYW1lJ10sCiAgICAgICAgICAgICAgICAkYXJndW1lbnRzWyRkb21haW5bJ3BhcmFtZXRlciddXQogICAgICAgICAgICApKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgcHJpdmF0ZSBmdW5jdGlvbiBnZXRfZG9tYWlucygkZG9jX2Jsb2NrKSB7CiAgICAgICAgJGxpbmVzID0gZXhwbG9kZSgiXG4iLCAkZG9jX2Jsb2NrKTsKICAgICAgICAkZG9tYWlucyA9IGFycmF5KCk7CiAgICAgICAgJGRvbWFpbl90YWcgPSBEb21haW5WYWxpZGF0b3I6OkRPTUFJTl9UQUcgLiAnICc7CiAgICAgICAgZm9yZWFjaCAoJGxpbmVzIGFzICRsaW5lKSB7CiAgICAgICAgICAgICRoYXNfZG9tYWluID0gc3RyaXN0cigkbGluZSwgJGRvbWFpbl90YWcpICE9PSBmYWxzZTsKICAgICAgICAgICAgaWYgKCRoYXNfZG9tYWluKSB7CiAgICAgICAgICAgICAgICAkZG9tYWluX2luZm8gPSBleHBsb2RlKCRkb21haW5fdGFnLCAkbGluZSk7CiAgICAgICAgICAgICAgICAkZG9tYWluX2luZm8gPSBleHBsb2RlKCcgJywgJGRvbWFpbl9pbmZvWzFdKTsKICAgICAgICAgICAgICAgICRkb21haW5zW10gPSBhcnJheSgKICAgICAgICAgICAgICAgICAgICAnbmFtZScgICAgICA9PiAkZG9tYWluX2luZm9bMF0sCiAgICAgICAgICAgICAgICAgICAgJ3BhcmFtZXRlcicgPT4gJGRvbWFpbl9pbmZvWzFdLAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gJGRvbWFpbnM7CiAgICB9CgogICAgcHJpdmF0ZSBmdW5jdGlvbiBwYXJzZV9hcmd1bWVudHMoJHBhcmFtZXRlcnMsICR2YWx1ZXMpIHsKICAgICAgICAkcmV0ID0gYXJyYXkoKTsKICAgICAgICBmb3IgKCRpID0gMCwgJHNpemUgPSBzaXplb2YoJHZhbHVlcyk7ICRpIDwgJHNpemU7ICRpKyspIHsKICAgICAgICAgICAgJHJldFskcGFyYW1ldGVyc1skaV0tPm5hbWVdID0gJHZhbHVlc1skaV07CiAgICAgICAgfQogICAgICAgIHJldHVybiAkcmV0OwogICAgfQp9CgpjbGFzcyBGb29Eb21haW4gewogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiBpc19ub3RfZW1wdHkoJGlucHV0KSB7CiAgICAgICAgcmV0dXJuICFlbXB0eSgkaW5wdXQpOwogICAgfQp9CgpjbGFzcyBGb28gewogICAgLyoqCiAgICAgKiBAZG9tYWluIEZvb0RvbWFpbjo6aXNfbm90X2VtcHR5IG15X3N0cmluZwogICAgICovCiAgICBwdWJsaWMgZnVuY3Rpb24gcHJpbnRfc3RyaW5nKCRteV9zdHJpbmcpIHsKICAgICAgICBlY2hvICRteV9zdHJpbmcgLiBQSFBfRU9MOwogICAgfQp9CgokZm9vID0gbmV3IERvbWFpblZhbGlkYXRvcihuZXcgRm9vKCkpOwokZm9vLT5wcmludF9zdHJpbmcoJ0hlbGxvLCB3b3JsZCEnKTsKdHJ5IHsKICAgICRmb28tPnByaW50X3N0cmluZygnJyk7IC8vIHRocm93cyBhIERvbWFpbkV4Y2VwdGlvbgp9IGNhdGNoIChcRG9tYWluRXhjZXB0aW9uICRlKSB7CiAgICBlY2hvICdDb3VsZCBub3QgcHJpbnQgYW4gZW1wdHkgc3RyaW5nLi4uJyAuIFBIUF9FT0w7Cn0K