Пример #1
0
 /**
  * Returns the hash.
  *
  * @return string
  */
 public function getHash()
 {
     // Never remove the database from the identifier
     // Most SQL queries do not include the target database
     $identifier = $this->reflector->getDatabase() . $this->reflector->getSql() . serialize($this->reflector->getParameters());
     return md5($identifier);
 }
Пример #2
0
 /**
  * Parse the annotations for a given Reflector.
  * Annotations are derived from doc comments, and are similar to Java's.
  *
  * Annotation syntax is simple:
  *
  * :foo = expr
  *
  * Where 'expr' is a valid JSON expression containing no new lines.
  * We also support single values, not nested in arrays/objects.
  * You can't use any null expressions - this would be seen as a syntax
  * error. You can, of course, create arrays/objects containing nulls.
  *
  * It's also valid to do:
  *
  * :foo
  *
  * Which is simply a shortcut for
  *
  * :foo = true
  *
  * The JSON is subject to whatever nuances affect PHP's json_decode().
  * Particularly, string keys must always be enclosed in quotes, and
  * all string quoting must be done with double quotes.
  *
  * Example usage:
  *
  * :requires_super_user = true
  * :requires_privileges = { "foo": "crude" }
  *
  * You can build up arrays on separate lines for clarity:
  *
  * :extensions[]        = { "name": "Extension1", "param": "foo" }
  * :extensions[]        = { "name": "Extension2", "param": "bar" }
  *
  * @todo this method should cache its results as the builder hammers it pretty hard
  *
  * @param $r <tt>Reflector</tt> for which to parse annotations
  * @return associative array of annotations for <tt>$r</tt>
  */
 public static function parse(\Reflector $r)
 {
     $comment = $r->getDocComment();
     if (strlen($comment) == 0 || strpos($comment, ':') === false) {
         return array();
     }
     $annotations = array();
     preg_match_all('/\\*\\s+:(\\w+)(\\[\\])?\\s*(=\\s*(.*))?$/m', $comment, $matches, PREG_SET_ORDER);
     foreach ($matches as $m) {
         if (!isset($m[4])) {
             $decode = true;
         } else {
             $json = trim($m[4]);
             if ($json[0] == '[' || $json[0] == '{') {
                 $decode = json_decode($json, true);
             } else {
                 $decode = json_decode('[' . $json . ']', true);
                 if (is_array($decode)) {
                     $decode = $decode[0];
                 }
             }
         }
         if ($decode === null) {
             throw new Error_Syntax("Invalid JSON fragment: {$json}");
         }
         if ($m[2] == '[]') {
             $annotations[$m[1]][] = $decode;
         } else {
             $annotations[$m[1]] = $decode;
         }
     }
     return $annotations;
 }
Пример #3
0
 /**
  * @param \Reflector $reflection
  * @param string $type
  *   If we are not reflecting the class itself, specify "Method", "Property", etc.
  *
  * @return array
  */
 public static function getCodeDocs($reflection, $type = NULL)
 {
     $docs = self::parseDocBlock($reflection->getDocComment());
     // Recurse into parent functions
     if (isset($docs['inheritDoc'])) {
         unset($docs['inheritDoc']);
         $newReflection = NULL;
         try {
             if ($type) {
                 $name = $reflection->getName();
                 $reflectionClass = $reflection->getDeclaringClass()->getParentClass();
                 if ($reflectionClass) {
                     $getItem = "get{$type}";
                     $newReflection = $reflectionClass->{$getItem}($name);
                 }
             } else {
                 $newReflection = $reflection->getParentClass();
             }
         } catch (\ReflectionException $e) {
         }
         if ($newReflection) {
             // Mix in
             $additionalDocs = self::getCodeDocs($newReflection, $type);
             if (!empty($docs['comment']) && !empty($additionalDocs['comment'])) {
                 $docs['comment'] .= "\n\n" . $additionalDocs['comment'];
             }
             $docs += $additionalDocs;
         }
     }
     return $docs;
 }
Пример #4
0
	protected function _make_internal_message(\Reflector $reflection) {
		$type = false;
		$name = false;
		$location = false;
		
		if($reflection instanceof \ReflectionFunction) {
			$type = 'function';
			$name = $reflection->name;
		}
		elseif($reflection instanceof \ReflectionClass) {
			$type = 'class';
			$name = $reflection->name;
		}
		elseif($reflection instanceof \ReflectionMethod) {
			$type = 'method';
			$name = $reflection->getDeclaringClass()->name . '::' . $reflection->name;
		}
		
		$location = $reflection->getFileName() . ':' . $reflection->getStartLine();
		
		Ev\Evaluer::make_internal_from(
			Ev\Evaluer::SOURCE_OUTPUT,
			sprintf("Source Code for %s '%s' (%s)", $type, $name, $location)
		);
	}
Пример #5
0
function getAnnotation(Reflector $ref)
{
    $doc = $ref->getDocComment();
    $annotations = array();
    if ($doc !== false) {
        $pattern = '/@\\s*(\\w+)\\s*(?:\\((.+)\\))?/i';
        if (preg_match($pattern, $doc)) {
            preg_match_all($pattern, $doc, $annotation_matches);
            for ($i = 0; $i < count($annotation_matches[0]); $i++) {
                if (class_exists($annotation_matches[1][$i])) {
                    $_class = new $annotation_matches[1][$i]();
                    if ($_class instanceof Annotation) {
                        $annotations[$annotation_matches[1][$i]] = $_class;
                        if (!empty($annotation_matches[2][$i]) && preg_match('/^(?:\\s*\\w+\\s*=\\s*\\w+\\s*,?)+$/i', $annotation_matches[2][$i])) {
                            preg_match_all('/(\\w+)\\s*=\\s*(\\w+)\\s*,?/i', $annotation_matches[2][$i], $annotation_param_matches);
                            for ($j = 0; $j < count($annotation_param_matches[0]); $j++) {
                                $_property = $annotation_param_matches[1][$j];
                                if (property_exists($_class, $_property)) {
                                    $_class->{$_property} = $annotation_param_matches[2][$j];
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return $annotations;
}
Пример #6
0
 /**
  * Returns the first line of docblock.
  *
  * @param \Reflector $reflection
  * @return string
  */
 protected function parseDocCommentSummary($reflection)
 {
     $docLines = preg_split('~\\R~u', $reflection->getDocComment());
     if (isset($docLines[1])) {
         return trim($docLines[1], "\t *");
     }
     return '';
 }
Пример #7
0
 /**
  * @param $className
  * @return ClassEntity
  */
 private function loadClassEntity($className)
 {
     if (empty($this->cache[$className])) {
         $reflector = new Reflector($className, $this);
         $this->cache[$className] = $reflector->getClassEntity();
     }
     return $this->cache[$className];
 }
Пример #8
0
 /**
  *  create an annotation from the given reflection
  *
  *  @param  \Reflector  $reflection   
  */
 public function __construct(\Reflector $reflection)
 {
     $this->reflection = $reflection;
     if ($docblock = $reflection->getDocComment()) {
         $this->rdocblock = new ReflectionDocBlock($docblock);
     }
     //if
 }
 /**
  * Get defined constants for the given class or object Reflector.
  *
  * @param \Reflector $reflector        	
  *
  * @return array
  */
 protected function getConstants(\Reflector $reflector)
 {
     $constants = array();
     foreach ($reflector->getConstants() as $name => $constant) {
         $constants[$name] = new ReflectionConstant($reflector, $name);
     }
     // TODO: this should be natcasesort
     ksort($constants);
     return $constants;
 }
 /**
  * Get defined constants for the given class or object Reflector.
  *
  * @param \Reflector $reflector
  *
  * @return array
  */
 protected function getConstants(\Reflector $reflector)
 {
     $constants = array();
     foreach ($reflector->getConstants() as $name => $constant) {
         $constants[$name] = new ReflectionConstant($reflector, $name);
     }
     // Removed task from comment. SPV
     ksort($constants);
     return $constants;
 }
 /**
  * @param  \Reflector $reflected
  * @return string
  */
 public function getDocCommentText(\Reflector $reflected)
 {
     $comment = $reflected->getDocComment();
     // Remove PHPDoc
     $comment = preg_replace('/^\\s+\\* @[\\w0-9]+.*/msi', '', $comment);
     // let's clean the doc block
     $comment = str_replace('/**', '', $comment);
     $comment = str_replace('*/', '', $comment);
     $comment = preg_replace('/^\\s*\\* ?/m', '', $comment);
     return trim($comment);
 }
 /**
  * Get defined methods for the given class or object Reflector.
  *
  * @param bool       $showAll   Include private and protected methods.
  * @param \Reflector $reflector
  *
  * @return array
  */
 protected function getMethods($showAll, \Reflector $reflector)
 {
     $methods = array();
     foreach ($reflector->getMethods() as $name => $method) {
         if ($showAll || $method->isPublic()) {
             $methods[$method->getName()] = $method;
         }
     }
     // Removed task from comment. SPV
     ksort($methods);
     return $methods;
 }
 /**
  * Get defined properties for the given class or object Reflector.
  *
  * @param bool       $showAll   Include private and protected properties.
  * @param \Reflector $reflector
  *
  * @return array
  */
 protected function getProperties($showAll, \Reflector $reflector)
 {
     $properties = array();
     foreach ($reflector->getProperties() as $property) {
         if ($showAll || $property->isPublic()) {
             $properties[$property->getName()] = $property;
         }
     }
     // Removed task from comment. SPV
     ksort($properties);
     return $properties;
 }
Пример #14
0
 /**
  * Get defined methods for the given class or object Reflector.
  *
  * @param boolean    $showAll   Include private and protected methods.
  * @param \Reflector $reflector
  *
  * @return array
  */
 protected function getMethods($showAll, \Reflector $reflector)
 {
     $methods = array();
     foreach ($reflector->getMethods() as $name => $method) {
         if ($showAll || $method->isPublic()) {
             $methods[$method->getName()] = $method;
         }
     }
     // TODO: this should be natcasesort
     ksort($methods);
     return $methods;
 }
Пример #15
0
 /**
  * Get defined properties for the given class or object Reflector.
  *
  * @param bool       $showAll   Include private and protected properties.
  * @param \Reflector $reflector
  *
  * @return array
  */
 protected function getProperties($showAll, \Reflector $reflector)
 {
     $properties = array();
     foreach ($reflector->getProperties() as $property) {
         if ($showAll || $property->isPublic()) {
             $properties[$property->getName()] = $property;
         }
     }
     // TODO: this should be natcasesort
     ksort($properties);
     return $properties;
 }
Пример #16
0
 /**
  * Returns an annotation value.
  * @return string|NULL
  */
 public static function parseAnnotation(\Reflector $ref, $name)
 {
     static $ok;
     if (!$ok) {
         if (!(new \ReflectionMethod(__METHOD__))->getDocComment()) {
             throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
         }
         $ok = TRUE;
     }
     if ($ref->getDocComment() && preg_match("#[\\s*]@{$name}(?:\\s++([^@]\\S*)?|\$)#", trim($ref->getDocComment(), '/*'), $m)) {
         return isset($m[1]) ? $m[1] : '';
     }
 }
Пример #17
0
function get_comment(Reflector $reflector)
{
    $comments = explode("\n", $reflector->getDocComment());
    foreach ($comments as $line) {
        $nameStart = strpos($line, '@desc: ');
        if (FALSE === $nameStart) {
            continue;
        } else {
            return trim(substr($line, $nameStart + 6));
        }
    }
    return 'No description available!';
}
Пример #18
0
 /**
  * Parses and caches annotations.
  * @param  \ReflectionClass|\ReflectionMethod|\ReflectionProperty
  * @return array
  */
 public static function &init(Reflector $r)
 {
     $cache =& self::$cache[$r->getName()];
     if ($r instanceof ReflectionClass) {
         $cache =& $cache[''];
     } elseif ($r instanceof ReflectionMethod) {
         $cache =& $cache[$r->getDeclaringClass()->getName()];
     } else {
         $cache =& $cache['$' . $r->getDeclaringClass()->getName()];
     }
     if ($cache !== NULL) {
         return $cache;
     }
     preg_match_all('#@([a-zA-Z0-9_]+)(?:\\(((?>[^\'")]+|\'[^\']*\'|"[^"]*")*)\\))?#', $r->getDocComment(), $matches, PREG_SET_ORDER);
     $cache = array();
     foreach ($matches as $match) {
         if (isset($match[2])) {
             preg_match_all('#[,\\s](?>([a-zA-Z0-9_]+)\\s*=\\s*)?([^\'",\\s][^,]*|\'[^\']*\'|"[^"]*")#', ',' . $match[2], $matches, PREG_SET_ORDER);
             $items = array();
             $key = '';
             $val = TRUE;
             foreach ($matches as $m) {
                 list(, $key, $val) = $m;
                 if ($val[0] === "'" || $val[0] === '"') {
                     $val = substr($val, 1, -1);
                 } elseif (strcasecmp($val, 'true') === 0) {
                     $val = TRUE;
                 } elseif (strcasecmp($val, 'false') === 0) {
                     $val = FALSE;
                 } elseif (strcasecmp($val, 'null') === 0) {
                     $val = NULL;
                 } elseif (is_numeric($val)) {
                     $val = 1 * $val;
                 }
                 if ($key === '') {
                     $items[] = $val;
                 } else {
                     $items[$key] = $val;
                 }
             }
             $items = count($items) < 2 && $key === '' ? $val : new ArrayObject($items, ArrayObject::ARRAY_AS_PROPS);
         } else {
             $items = TRUE;
         }
         $cache[$match[1]][] = $items;
     }
     return $cache;
 }
Пример #19
0
    /**
     * Constructor
     *
     * @param Reflector|string $commentOrReflector
     * @param AnnotationManager|null $annotationManager
     * @return \Zend\Code\Reflection\DocBlockReflection
     */
    public function __construct($commentOrReflector, AnnotationManager $annotationManager = null)
    {
        if ($commentOrReflector instanceof \Reflector) {
            $this->reflector = $commentOrReflector;
            if (!method_exists($commentOrReflector, 'getDocComment')) {
                throw new Exception\InvalidArgumentException('Reflector must contain method "getDocComment"');
            }
            $this->docComment = $commentOrReflector->getDocComment();

            $lineCount = substr_count($this->docComment, "\n");

            $this->startLine = $this->reflector->getStartLine() - $lineCount - 1;
            $this->endLine   = $this->reflector->getStartLine() - 1;
        } elseif (is_string($commentOrReflector)) {
            $this->docComment = $commentOrReflector;
        } else {
            throw new Exception\InvalidArgumentException(get_class($this) . ' must have a (string) DocComment or a Reflector in the constructor');
        }

        if ($this->docComment == '') {
            throw new Exception\InvalidArgumentException('DocComment cannot be empty');
        }

        $this->annotationManager = $annotationManager;
    }
Пример #20
0
 /**
  * Constructor
  *
  * @param Reflector|string $commentOrReflector
  */
 public function __construct($commentOrReflector)
 {
     if ($commentOrReflector instanceof Reflector) {
         $this->_reflector = $commentOrReflector;
         if (!method_exists($commentOrReflector, 'getDocComment')) {
             // require_once 'Zend/Reflection/Exception.php';
             throw new Zend_Reflection_Exception('Reflector must contain method "getDocComment"');
         }
         $docComment = $commentOrReflector->getDocComment();
         $lineCount = substr_count($docComment, "\n");
         $this->_startLine = $this->_reflector->getStartLine() - $lineCount - 1;
         $this->_endLine = $this->_reflector->getStartLine() - 1;
     } elseif (is_string($commentOrReflector)) {
         $docComment = $commentOrReflector;
     } else {
         // require_once 'Zend/Reflection/Exception.php';
         throw new Zend_Reflection_Exception(get_class($this) . ' must have a (string) DocComment or a Reflector in the constructor');
     }
     if ($docComment == '') {
         // require_once 'Zend/Reflection/Exception.php';
         throw new Zend_Reflection_Exception('DocComment cannot be empty');
     }
     $this->_docComment = $docComment;
     $this->_parse();
 }
Пример #21
0
 /**
  * Constructor
  *
  * @param ReflectionFunction $r
  */
 public function __construct(\Reflector $r, $namespace = null, $argv = array())
 {
     // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x,
     // both extend ReflectionFunctionAbstract. So, we can't do normal type
     // hinting in the prototype, but instead need to do some explicit
     // testing here.
     if (!$r instanceof \ReflectionFunction && !$r instanceof \ReflectionMethod) {
         throw new Exception\InvalidArgumentException('Invalid reflection class');
     }
     $this->reflection = $r;
     // Determine namespace
     if (null !== $namespace) {
         $this->setNamespace($namespace);
     }
     // Determine arguments
     if (is_array($argv)) {
         $this->argv = $argv;
     }
     // If method call, need to store some info on the class
     if ($r instanceof \ReflectionMethod) {
         $this->class = $r->getDeclaringClass()->getName();
     }
     // Perform some introspection
     $this->_reflect();
 }
Пример #22
0
 /**
  * Returns the ReflectionClass of the given Reflector.
  *
  * @param \Reflector $reflector
  *
  * @return \ReflectionClass|null
  */
 private function getDeclaringClass(\Reflector $reflector)
 {
     if ($reflector instanceof \ReflectionClass) {
         return $reflector;
     }
     if ($reflector instanceof \ReflectionProperty) {
         return $reflector->getDeclaringClass();
     }
     if ($reflector instanceof \ReflectionMethod) {
         return $reflector->getDeclaringClass();
     }
     if ($reflector instanceof \ReflectionParameter) {
         return $reflector->getDeclaringClass();
     }
     return null;
 }
 /**
  * Builds an instance of the given type.
  *
  * @param string  $type
  * @param mixed[] $arguments
  * @param bool    $isSingleton
  *
  * @return object
  */
 private function buildInstance($type, array $arguments = [], $isSingleton = true)
 {
     $class = $type;
     if (isset($this->interfaces[$class])) {
         $class = $this->interfaces[$class];
     }
     $key = $this->buildKey($class, $arguments);
     if ($isSingleton && isset($this->objects[$key])) {
         return $this->objects[$class];
     }
     if (isset($this->processing[$class])) {
         return;
     }
     $this->processing[$class] = true;
     if (isset($this->factories[$class])) {
         $factory = $this->factories[$class];
         $parameters = $this->resolveObjects($this->reflector->resolveFunctionParameters($factory, $arguments), 'Closure');
         $result = $factory(...$parameters);
     } else {
         if (!$this->reflector->isInstantiable($class)) {
             throw new \RuntimeException(sprintf('"%s" is not instantiable.', $class));
         }
         $parameters = $this->resolveObjects($this->reflector->resolveMethodParameters($class, '__construct', $arguments), $class);
         $result = new $class(...$parameters);
     }
     if ($isSingleton) {
         $this->registerInstance($key, $result);
     }
     unset($this->processing[$class]);
     return $result;
 }
Пример #24
0
 /**
  * @param \Reflector $reflector
  * @param string $tagName
  *
  * @return string|null
  */
 public function resolveElementType(\Reflector $reflector, $tagName)
 {
     $docBlock = new DocBlock($reflector);
     $returnTags = $docBlock->getTagsByName($tagName);
     /** @var ReturnTag $returnTag */
     $returnTag = reset($returnTags);
     $type = $returnTag->getType();
     $isCollection = false;
     if ($extractedType = $this->extractTypeFromCollectionType($type)) {
         $isCollection = true;
         $type = $extractedType;
     }
     if (static::isTypeObject($type) && ($reflector instanceof \ReflectionMethod || $reflector instanceof \ReflectionProperty)) {
         $type = $this->resolveClassName($type, $reflector->getDeclaringClass());
     }
     return $type . ($isCollection ? '[]' : '');
 }
Пример #25
0
 public function getType(\Reflector $reflector)
 {
     if (!$reflector instanceof \ReflectionProperty && !$reflector instanceof \ReflectionMethod) {
         throw new \InvalidArgumentException('Argument "reflector" should be instance of \\ReflectionProperty or \\ReflectionMethod');
     }
     if (null === ($tokenizedClass = $this->getTokenizedReflectionClass($reflector->getDeclaringClass()))) {
         return null;
     }
     if ($reflector instanceof \ReflectionProperty) {
         $name = self::PROPERTY_ANNOTATION_NAME;
         $annotations = $tokenizedClass->getProperty($reflector->name)->getAnnotations();
     } else {
         $name = self::METHOD_ANNOTATION_NAME;
         $annotations = $tokenizedClass->getMethod($reflector->name)->getAnnotations();
     }
     return isset($annotations[$name]) ? $this->parseType($annotations[$name], $tokenizedClass) : null;
 }
Пример #26
0
 /**
  * Format the code represented by $reflector.
  *
  * @param \Reflector $reflector
  *
  * @return string formatted code
  */
 public static function format(\Reflector $reflector)
 {
     if ($fileName = $reflector->getFileName()) {
         if (!is_file($fileName)) {
             throw new RuntimeException('Source code unavailable.');
         }
         $file = file_get_contents($fileName);
         $lines = preg_split('/\\r?\\n/', $file);
         $start = $reflector->getStartLine() - 1;
         $end = $reflector->getEndLine() - $start;
         $code = array_slice($lines, $start, $end);
         // no need to escape this bad boy, since (for now) it's being output raw.
         // return OutputFormatter::escape(implode(PHP_EOL, $code));
         return implode(PHP_EOL, $code);
     } else {
         throw new RuntimeException('Source code unavailable.');
     }
 }
Пример #27
0
 /**
  * @return bool
  */
 protected function isGetter()
 {
     if (!$this->isMethod()) {
         return false;
     }
     $name = $this->reflector->getName();
     $parse = substr($name, 0, 3);
     return $parse == 'get';
 }
Пример #28
0
 /**
  * Returns annotations.
  * @param  \ReflectionClass|\ReflectionMethod|\ReflectionProperty
  * @return array
  */
 public static function getAll(\Reflector $r)
 {
     if ($r instanceof \ReflectionClass) {
         $type = $r->getName();
         $member = '';
     } elseif ($r instanceof \ReflectionMethod) {
         $type = $r->getDeclaringClass()->getName();
         $member = $r->getName();
     } else {
         $type = $r->getDeclaringClass()->getName();
         $member = '$' . $r->getName();
     }
     if (!self::$useReflection) {
         // auto-expire cache
         $file = $r instanceof \ReflectionClass ? $r->getFileName() : $r->getDeclaringClass()->getFileName();
         // will be used later
         if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) {
             unset(self::$cache[$type]);
         }
         unset(self::$timestamps[$file]);
     }
     if (isset(self::$cache[$type][$member])) {
         // is value cached?
         return self::$cache[$type][$member];
     }
     if (self::$useReflection === NULL) {
         // detects whether is reflection available
         $self_reflection = new \ReflectionClass(__CLASS__);
         self::$useReflection = (bool) $self_reflection->getDocComment();
     }
     if (self::$useReflection) {
         return self::$cache[$type][$member] = self::parseComment($r->getDocComment());
     } else {
         if (self::$cache === NULL) {
             self::$cache = (array) self::getCache()->offsetGet('list');
             self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array();
         }
         if (!isset(self::$cache[$type]) && $file) {
             self::$cache['*'][$file] = filemtime($file);
             self::parseScript($file);
             self::getCache()->save('list', self::$cache);
         }
         if (isset(self::$cache[$type][$member])) {
             return self::$cache[$type][$member];
         } else {
             return self::$cache[$type][$member] = array();
         }
     }
 }
Пример #29
0
 /**
  * Format the code represented by $reflector.
  *
  * @param \Reflector $reflector
  *
  * @return string formatted code
  */
 public static function format(\Reflector $reflector)
 {
     if ($fileName = $reflector->getFileName()) {
         if (!is_file($fileName)) {
             throw new RuntimeException('Source code unavailable.');
         }
         $file = file_get_contents($fileName);
         $start = $reflector->getStartLine();
         $end = $reflector->getEndLine() - $start;
         $colors = new ConsoleColor();
         $colors->addTheme('line_number', array('blue'));
         $highlighter = new Highlighter($colors);
         return $highlighter->getCodeSnippet($file, $start, 0, $end);
         // no need to escape this bad boy, since (for now) it's being output raw.
         // return OutputFormatter::escape(implode(PHP_EOL, $code));
         return implode(PHP_EOL, $code);
     } else {
         throw new RuntimeException('Source code unavailable.');
     }
 }
Пример #30
0
 /**
  * @param \Reflector $thing
  * @throws \Exception
  * @return callable
  */
 protected function _getConfigGetter(\Reflector $thing = null)
 {
     $reader = $this->_getAnnotationReader();
     $annNS = $this->annNS;
     if ($thing === null) {
         return function ($ann) use($reader, $annNS) {
             return $reader->getSingleClassAnnotation($annNS . $ann);
         };
     }
     if ($thing instanceof \ReflectionMethod) {
         return function ($ann) use($reader, $thing, $annNS) {
             return $reader->getSingleMethodAnnotation($thing->getName(), $annNS . $ann);
         };
     }
     if ($thing instanceof \ReflectionProperty) {
         return function ($ann) use($reader, $thing, $annNS) {
             return $reader->getSinglePropertyAnnotation($thing->getName(), $annNS . $ann);
         };
     }
     throw new \Exception("Unable to work out how to configure a " . get_class($thing));
 }