PageRenderTime 21ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/treeview-master/libs/Nette/Reflection/AnnotationsParser.php

https://github.com/indesigner/tests
PHP | 288 lines | 222 code | 34 blank | 32 comment | 27 complexity | af19d9a0256b1ebe56c3ec717fe18076 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Reflection
  10. */
  11. /**
  12. * Annotations support for PHP.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette\Reflection
  16. */
  17. final class AnnotationsParser
  18. {
  19. /** @var bool */
  20. public static $useReflection;
  21. /** @var array */
  22. private static $cache;
  23. /** @var array */
  24. private static $timestamps;
  25. /**
  26. * Static class - cannot be instantiated.
  27. */
  28. final public function __construct()
  29. {
  30. throw new LogicException("Cannot instantiate static class " . get_class($this));
  31. }
  32. /**
  33. * Returns annotations.
  34. * @param ReflectionClass|\ReflectionMethod|\ReflectionProperty
  35. * @return array
  36. */
  37. public static function getAll(Reflector $r)
  38. {
  39. if ($r instanceof ReflectionClass) {
  40. $type = $r->getName();
  41. $member = '';
  42. } elseif ($r instanceof ReflectionMethod) {
  43. $type = $r->getDeclaringClass()->getName();
  44. $member = $r->getName();
  45. } else {
  46. $type = $r->getDeclaringClass()->getName();
  47. $member = '$' . $r->getName();
  48. }
  49. if (!self::$useReflection) { // auto-expire cache
  50. $file = $r instanceof ReflectionClass ? $r->getFileName() : $r->getDeclaringClass()->getFileName(); // will be used later
  51. if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) {
  52. unset(self::$cache[$type]);
  53. }
  54. unset(self::$timestamps[$file]);
  55. }
  56. if (isset(self::$cache[$type][$member])) { // is value cached?
  57. return self::$cache[$type][$member];
  58. }
  59. if (self::$useReflection === NULL) { // detects whether is reflection available
  60. self::$useReflection = (bool) ClassReflection::from(__CLASS__)->getDocComment();
  61. }
  62. if (self::$useReflection) {
  63. return self::$cache[$type][$member] = self::parseComment($r->getDocComment());
  64. } else {
  65. if (self::$cache === NULL) {
  66. self::$cache = (array) self::getCache()->offsetGet('list');
  67. self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array();
  68. }
  69. if (!isset(self::$cache[$type]) && $file) {
  70. self::$cache['*'][$file] = filemtime($file);
  71. self::parseScript($file);
  72. self::getCache()->save('list', self::$cache);
  73. }
  74. if (isset(self::$cache[$type][$member])) {
  75. return self::$cache[$type][$member];
  76. } else {
  77. return self::$cache[$type][$member] = array();
  78. }
  79. }
  80. }
  81. /**
  82. * Parses phpDoc comment.
  83. * @param string
  84. * @return array
  85. */
  86. private static function parseComment($comment)
  87. {
  88. static $tokens = array('true' => TRUE, 'false' => FALSE, 'null' => NULL, '' => TRUE);
  89. preg_match_all('#@([a-zA-Z0-9_]+)([\s(].*)#', substr($comment, 0, -2) . ' ', $matches, PREG_SET_ORDER);
  90. $res = array();
  91. foreach ($matches as $match)
  92. {
  93. list(, $name, $value) = $match;
  94. if ($value[0] === '(') {
  95. $items = array();
  96. $key = '';
  97. $val = TRUE;
  98. $value[0] = ',';
  99. while (preg_match('#\s*,\s*(?>([a-zA-Z0-9_]+)\s*=\s*)?([^\'"),\s][^),]*|\'[^\']*\'|"[^"]*")#A', $value, $m)) {
  100. $value = substr($value, strlen($m[0]));
  101. list(, $key, $val) = $m;
  102. if ($val[0] === "'" || $val[0] === '"') {
  103. $val = substr($val, 1, -1);
  104. } elseif (is_numeric($val)) {
  105. $val = 1 * $val;
  106. } else {
  107. $lval = strtolower($val);
  108. $val = array_key_exists($lval, $tokens) ? $tokens[$lval] : $val;
  109. }
  110. if ($key === '') {
  111. $items[] = $val;
  112. } else {
  113. $items[$key] = $val;
  114. }
  115. }
  116. $value = count($items) < 2 && $key === '' ? $val : $items;
  117. } else {
  118. $value = trim($value);
  119. if (is_numeric($value)) {
  120. $value = 1 * $value;
  121. } else {
  122. $lval = strtolower($value);
  123. $value = array_key_exists($lval, $tokens) ? $tokens[$lval] : $value;
  124. }
  125. }
  126. $class = $name . 'Annotation';
  127. if (class_exists($class)) {
  128. $res[$name][] = new $class(is_array($value) ? $value : array('value' => $value));
  129. } else {
  130. $res[$name][] = is_array($value) ? new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS) : $value;
  131. }
  132. }
  133. return $res;
  134. }
  135. /**
  136. * Parses PHP file.
  137. * @param string
  138. * @return void
  139. */
  140. private static function parseScript($file)
  141. {
  142. if (!defined('T_NAMESPACE')) {
  143. define('T_NAMESPACE', -1);
  144. define('T_NS_SEPARATOR', -1);
  145. }
  146. $s = file_get_contents($file);
  147. if (preg_match('#//nette'.'loader=(\S*)#', $s)) {
  148. return; // TODO: allways ignore?
  149. }
  150. $expected = $namespace = $class = $docComment = NULL;
  151. $level = $classLevel = 0;
  152. foreach (token_get_all($s) as $token)
  153. {
  154. if (is_array($token)) {
  155. switch ($token[0]) {
  156. case T_DOC_COMMENT:
  157. $docComment = $token[1];
  158. case T_WHITESPACE:
  159. case T_COMMENT:
  160. continue 2;
  161. case T_STRING:
  162. case T_NS_SEPARATOR:
  163. case T_VARIABLE:
  164. if ($expected) {
  165. $name .= $token[1];
  166. }
  167. continue 2;
  168. case T_FUNCTION:
  169. case T_VAR:
  170. case T_PUBLIC:
  171. case T_PROTECTED:
  172. case T_NAMESPACE:
  173. case T_CLASS:
  174. case T_INTERFACE:
  175. $expected = $token[0];
  176. $name = NULL;
  177. continue 2;
  178. case T_STATIC:
  179. case T_ABSTRACT:
  180. case T_FINAL:
  181. continue 2; // ignore in expectation
  182. case T_CURLY_OPEN:
  183. case T_DOLLAR_OPEN_CURLY_BRACES:
  184. $level++;
  185. }
  186. }
  187. if ($expected) {
  188. switch ($expected) {
  189. case T_CLASS:
  190. case T_INTERFACE:
  191. $class = $namespace . $name;
  192. $classLevel = $level;
  193. $name = '';
  194. // break intentionally omitted
  195. case T_FUNCTION:
  196. if ($token === '&') continue 2; // ignore
  197. case T_VAR:
  198. case T_PUBLIC:
  199. case T_PROTECTED:
  200. if ($class && $name !== NULL && $docComment) {
  201. self::$cache[$class][$name] = self::parseComment($docComment);
  202. }
  203. break;
  204. case T_NAMESPACE:
  205. $namespace = $name . '\\';
  206. }
  207. $expected = $docComment = NULL;
  208. }
  209. if ($token === ';') {
  210. $docComment = NULL;
  211. } elseif ($token === '{') {
  212. $docComment = NULL;
  213. $level++;
  214. } elseif ($token === '}') {
  215. $level--;
  216. if ($level === $classLevel) {
  217. $class = NULL;
  218. }
  219. }
  220. }
  221. }
  222. /********************* backend ****************d*g**/
  223. /**
  224. * @return Cache
  225. */
  226. protected static function getCache()
  227. {
  228. return Environment::getCache('Nette.Annotations');
  229. }
  230. }