TokenParser.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the MIT license. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\Common\Annotations;
  20. /**
  21. * Parses a file for namespaces/use/class declarations.
  22. *
  23. * @author Fabien Potencier <fabien@symfony.com>
  24. * @author Christian Kaps <christian.kaps@mohiva.com>
  25. */
  26. class TokenParser
  27. {
  28. /**
  29. * The token list.
  30. *
  31. * @var array
  32. */
  33. private $tokens;
  34. /**
  35. * The number of tokens.
  36. *
  37. * @var int
  38. */
  39. private $numTokens = 0;
  40. /**
  41. * The current array pointer.
  42. *
  43. * @var int
  44. */
  45. private $pointer = 0;
  46. public function __construct($contents)
  47. {
  48. $this->tokens = token_get_all($contents);
  49. $this->numTokens = count($this->tokens);
  50. $this->pointer = 0;
  51. }
  52. /**
  53. * Gets the next non whitespace and non comment token.
  54. *
  55. * @param $docCommentIsComment
  56. * If TRUE then a doc comment is considered a comment and skipped.
  57. * If FALSE then only whitespace and normal comments are skipped.
  58. *
  59. * @return array The token if exists, null otherwise.
  60. */
  61. public function next($docCommentIsComment = TRUE)
  62. {
  63. for ($i = $this->pointer; $i < $this->numTokens; $i++) {
  64. $this->pointer++;
  65. if ($this->tokens[$i][0] === T_WHITESPACE ||
  66. $this->tokens[$i][0] === T_COMMENT ||
  67. ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)) {
  68. continue;
  69. }
  70. return $this->tokens[$i];
  71. }
  72. return null;
  73. }
  74. /**
  75. * Parse a single use statement.
  76. *
  77. * @return array A list with all found class names for a use statement.
  78. */
  79. public function parseUseStatement()
  80. {
  81. $class = '';
  82. $alias = '';
  83. $statements = array();
  84. $explicitAlias = false;
  85. while (($token = $this->next())) {
  86. $isNameToken = $token[0] === T_STRING || $token[0] === T_NS_SEPARATOR;
  87. if (!$explicitAlias && $isNameToken) {
  88. $class .= $token[1];
  89. $alias = $token[1];
  90. } else if ($explicitAlias && $isNameToken) {
  91. $alias .= $token[1];
  92. } else if ($token[0] === T_AS) {
  93. $explicitAlias = true;
  94. $alias = '';
  95. } else if ($token === ',') {
  96. $statements[strtolower($alias)] = $class;
  97. $class = '';
  98. $alias = '';
  99. $explicitAlias = false;
  100. } else if ($token === ';') {
  101. $statements[strtolower($alias)] = $class;
  102. break;
  103. } else {
  104. break;
  105. }
  106. }
  107. return $statements;
  108. }
  109. /**
  110. * Get all use statements.
  111. *
  112. * @param string $namespaceName The namespace name of the reflected class.
  113. * @return array A list with all found use statements.
  114. */
  115. public function parseUseStatements($namespaceName)
  116. {
  117. $statements = array();
  118. while (($token = $this->next())) {
  119. if ($token[0] === T_USE) {
  120. $statements = array_merge($statements, $this->parseUseStatement());
  121. continue;
  122. }
  123. if ($token[0] !== T_NAMESPACE || $this->parseNamespace() != $namespaceName) {
  124. continue;
  125. }
  126. // Get fresh array for new namespace. This is to prevent the parser to collect the use statements
  127. // for a previous namespace with the same name. This is the case if a namespace is defined twice
  128. // or if a namespace with the same name is commented out.
  129. $statements = array();
  130. }
  131. return $statements;
  132. }
  133. /**
  134. * Get the namespace.
  135. *
  136. * @return string The found namespace.
  137. */
  138. public function parseNamespace()
  139. {
  140. $name = '';
  141. while (($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR)) {
  142. $name .= $token[1];
  143. }
  144. return $name;
  145. }
  146. /**
  147. * Get the class name.
  148. *
  149. * @return string The foundclass name.
  150. */
  151. public function parseClass()
  152. {
  153. // Namespaces and class names are tokenized the same: T_STRINGs
  154. // separated by T_NS_SEPARATOR so we can use one function to provide
  155. // both.
  156. return $this->parseNamespace();
  157. }
  158. }