ClassMapGenerator.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. $classes = [];
  80. $namespace = '';
  81. for ($i = 0; isset($tokens[$i]); ++$i) {
  82. $token = $tokens[$i];
  83. if (!isset($token[1])) {
  84. continue;
  85. }
  86. $class = '';
  87. switch ($token[0]) {
  88. case T_NAMESPACE:
  89. $namespace = '';
  90. // If there is a namespace, extract it
  91. while (isset($tokens[++$i][1])) {
  92. if (\in_array($tokens[$i][0], [T_STRING, T_NS_SEPARATOR])) {
  93. $namespace .= $tokens[$i][1];
  94. }
  95. }
  96. $namespace .= '\\';
  97. break;
  98. case T_CLASS:
  99. case T_INTERFACE:
  100. case T_TRAIT:
  101. // Skip usage of ::class constant
  102. $isClassConstant = false;
  103. for ($j = $i - 1; $j > 0; --$j) {
  104. if (!isset($tokens[$j][1])) {
  105. break;
  106. }
  107. if (T_DOUBLE_COLON === $tokens[$j][0]) {
  108. $isClassConstant = true;
  109. break;
  110. } elseif (!\in_array($tokens[$j][0], [T_WHITESPACE, T_DOC_COMMENT, T_COMMENT])) {
  111. break;
  112. }
  113. }
  114. if ($isClassConstant) {
  115. break;
  116. }
  117. // Find the classname
  118. while (isset($tokens[++$i][1])) {
  119. $t = $tokens[$i];
  120. if (T_STRING === $t[0]) {
  121. $class .= $t[1];
  122. } elseif ('' !== $class && T_WHITESPACE === $t[0]) {
  123. break;
  124. }
  125. }
  126. $classes[] = ltrim($namespace.$class, '\\');
  127. break;
  128. default:
  129. break;
  130. }
  131. }
  132. return $classes;
  133. }
  134. }