ClassMapGenerator.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\ClassLoader;
  11. @trigger_error('The '.__NAMESPACE__.'\ClassMapGenerator class is deprecated since Symfony 3.3 and will be removed in 4.0. Use Composer instead.', \E_USER_DEPRECATED);
  12. /**
  13. * ClassMapGenerator.
  14. *
  15. * @author Gyula Sallai <salla016@gmail.com>
  16. *
  17. * @deprecated since version 3.3, to be removed in 4.0.
  18. */
  19. class ClassMapGenerator
  20. {
  21. /**
  22. * Generate a class map file.
  23. *
  24. * @param array|string $dirs Directories or a single path to search in
  25. * @param string $file The name of the class map file
  26. */
  27. public static function dump($dirs, $file)
  28. {
  29. $dirs = (array) $dirs;
  30. $maps = [];
  31. foreach ($dirs as $dir) {
  32. $maps = array_merge($maps, static::createMap($dir));
  33. }
  34. file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
  35. }
  36. /**
  37. * Iterate over all files in the given directory searching for classes.
  38. *
  39. * @param \Iterator|string $dir The directory to search in or an iterator
  40. *
  41. * @return array A class map array
  42. */
  43. public static function createMap($dir)
  44. {
  45. if (\is_string($dir)) {
  46. $dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
  47. }
  48. $map = [];
  49. foreach ($dir as $file) {
  50. if (!$file->isFile()) {
  51. continue;
  52. }
  53. $path = $file->getRealPath() ?: $file->getPathname();
  54. if ('php' !== pathinfo($path, \PATHINFO_EXTENSION)) {
  55. continue;
  56. }
  57. $classes = self::findClasses($path);
  58. if (\PHP_VERSION_ID >= 70000) {
  59. // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
  60. gc_mem_caches();
  61. }
  62. foreach ($classes as $class) {
  63. $map[$class] = $path;
  64. }
  65. }
  66. return $map;
  67. }
  68. /**
  69. * Extract the classes in the given file.
  70. *
  71. * @param string $path The file to check
  72. *
  73. * @return array The found classes
  74. */
  75. private static function findClasses($path)
  76. {
  77. $contents = file_get_contents($path);
  78. $tokens = token_get_all($contents);
  79. $nsTokens = [\T_STRING => true, \T_NS_SEPARATOR => true];
  80. if (\defined('T_NAME_QUALIFIED')) {
  81. $nsTokens[T_NAME_QUALIFIED] = true;
  82. }
  83. $classes = [];
  84. $namespace = '';
  85. for ($i = 0; isset($tokens[$i]); ++$i) {
  86. $token = $tokens[$i];
  87. if (!isset($token[1])) {
  88. continue;
  89. }
  90. $class = '';
  91. switch ($token[0]) {
  92. case \T_NAMESPACE:
  93. $namespace = '';
  94. // If there is a namespace, extract it
  95. while (isset($tokens[++$i][1])) {
  96. if (isset($nsTokens[$tokens[$i][0]])) {
  97. $namespace .= $tokens[$i][1];
  98. }
  99. }
  100. $namespace .= '\\';
  101. break;
  102. case \T_CLASS:
  103. case \T_INTERFACE:
  104. case \T_TRAIT:
  105. // Skip usage of ::class constant
  106. $isClassConstant = false;
  107. for ($j = $i - 1; $j > 0; --$j) {
  108. if (!isset($tokens[$j][1])) {
  109. break;
  110. }
  111. if (\T_DOUBLE_COLON === $tokens[$j][0]) {
  112. $isClassConstant = true;
  113. break;
  114. } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) {
  115. break;
  116. }
  117. }
  118. if ($isClassConstant) {
  119. break;
  120. }
  121. // Find the classname
  122. while (isset($tokens[++$i][1])) {
  123. $t = $tokens[$i];
  124. if (\T_STRING === $t[0]) {
  125. $class .= $t[1];
  126. } elseif ('' !== $class && \T_WHITESPACE === $t[0]) {
  127. break;
  128. }
  129. }
  130. $classes[] = ltrim($namespace.$class, '\\');
  131. break;
  132. default:
  133. break;
  134. }
  135. }
  136. return $classes;
  137. }
  138. }