Source for file AnnotationsParser.php
Documentation is available at AnnotationsParser.php
6: * @copyright Copyright (c) 2004, 2010 David Grudl
7: * @license http://nettephp.com/license Nette license
8: * @link http://nettephp.com
10: * @package Nette\Reflection
16: * Annotations support for PHP.
18: * @copyright Copyright (c) 2004, 2010 David Grudl
19: * @package Nette\Reflection
24: /** @ignore internal single & double quoted PHP string */
25: const RE_STRING =
'\'(?:\\\\.|[^\'\\\\])*\'|"(?:\\\\.|[^"\\\\])*"';
27: /** @ignore internal PHP identifier */
28: const RE_IDENTIFIER =
'[_a-zA-Z\x7F-\xFF][_a-zA-Z0-9\x7F-\xFF]*';
31: public static $useReflection;
34: private static $cache;
37: private static $timestamps;
42: * Static class - cannot be instantiated.
46: throw new LogicException("Cannot instantiate static class " .
get_class($this));
52: * Returns annotations.
53: * @param ReflectionClass|\ReflectionMethod|\ReflectionProperty
56: public static function getAll(Reflector $r)
58: if ($r instanceof
ReflectionClass) {
59: $type =
$r->getName();
62: } elseif ($r instanceof
ReflectionMethod) {
63: $type =
$r->getDeclaringClass()->getName();
64: $member =
$r->getName();
67: $type =
$r->getDeclaringClass()->getName();
68: $member =
'$' .
$r->getName();
71: if (!self::$useReflection) { // auto-expire cache
72: $file =
$r instanceof
ReflectionClass ?
$r->getFileName() :
$r->getDeclaringClass()->getFileName(); // will be used later
73: if ($file &&
isset(self::$timestamps[$file]) &&
self::$timestamps[$file] !==
filemtime($file)) {
74: unset(self::$cache[$type]);
76: unset(self::$timestamps[$file]);
79: if (isset(self::$cache[$type][$member])) { // is value cached?
80: return self::$cache[$type][$member];
83: if (self::$useReflection ===
NULL) { // detects whether is reflection available
84: self::$useReflection = (bool)
ClassReflection::from(__CLASS__
)->getDocComment();
87: if (self::$useReflection) {
88: return self::$cache[$type][$member] =
self::parseComment($r->getDocComment());
91: if (self::$cache ===
NULL) {
92: self::$cache = (array)
self::getCache()->offsetGet('list');
93: self::$timestamps =
isset(self::$cache['*']) ?
self::$cache['*'] :
array();
96: if (!isset(self::$cache[$type]) &&
$file) {
97: self::$cache['*'][$file] =
filemtime($file);
98: self::parseScript($file);
99: self::getCache()->save('list', self::$cache);
102: if (isset(self::$cache[$type][$member])) {
103: return self::$cache[$type][$member];
105: return self::$cache[$type][$member] =
array();
113: * Parses phpDoc comment.
117: private static function parseComment($comment)
119: static $tokens =
array('true' =>
TRUE, 'false' =>
FALSE, 'null' =>
NULL, '' =>
TRUE);
122: @('.
self::RE_IDENTIFIER.
')[ \t]* ## annotation
124: \((?>'.
self::RE_STRING.
'|[^\'")@]+)+\)| ## (value)
125: [^(@\r\n][^@\r\n]*|) ## value
126: ~xi', trim($comment, '/*'), $matches, PREG_SET_ORDER);
129: foreach ($matches as $match)
131: list(, $name, $value) =
$match;
133: if (substr($value, 0, 1) ===
'(') {
138: while (preg_match('#\s*,\s*(?>('.
self::RE_IDENTIFIER.
')\s*=\s*)?('.
self::RE_STRING.
'|[^\'"),\s][^\'"),]*)#A', $value, $m)) {
140: list(, $key, $val) =
$m;
141: if ($val[0] ===
"'" ||
$val[0] ===
'"') {
156: $items[$key] =
$val;
160: $value =
count($items) <
2 &&
$key ===
'' ?
$val :
$items;
165: $value =
1 *
$value;
173: $class =
$name .
'Annotation';
175: $res[$name][] =
new $class(is_array($value) ?
$value :
array('value' =>
$value));
178: $res[$name][] =
is_array($value) ?
new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS) :
$value;
192: private static function parseScript($file)
202: return; // TODO: allways ignore?
205: $expected =
$namespace =
$class =
$docComment =
NULL;
206: $level =
$classLevel =
0;
211: switch ($token[0]) {
213: $docComment =
$token[1];
219: case T_NS_SEPARATOR:
233: $expected =
$token[0];
240: continue 2; // ignore in expectation
243: case T_DOLLAR_OPEN_CURLY_BRACES:
249: switch ($expected) {
252: $class =
$namespace .
$name;
253: $classLevel =
$level;
255: // break intentionally omitted
257: if ($token ===
'&') continue 2; // ignore
261: if ($class &&
$name !==
NULL &&
$docComment) {
262: self::$cache[$class][$name] =
self::parseComment($docComment);
267: $namespace =
$name .
'\\';
270: $expected =
$docComment =
NULL;
273: if ($token ===
';') {
275: } elseif ($token ===
'{') {
278: } elseif ($token ===
'}') {
280: if ($level ===
$classLevel) {
289: /********************* backend ****************d*g**/