/src/Composer/Autoload/ClassMapGenerator.php

https://github.com/benja-M-1/composer · PHP · 145 lines · 86 code · 22 blank · 37 comment · 17 complexity · 927a9172c875140e1345ec7fec39fcdc MD5 · raw file

  1. <?php
  2. /*
  3. * This file is copied from 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. * @license MIT
  11. */
  12. namespace Composer\Autoload;
  13. /**
  14. * ClassMapGenerator
  15. *
  16. * @author Gyula Sallai <salla016@gmail.com>
  17. */
  18. class ClassMapGenerator
  19. {
  20. /**
  21. * Generate a class map file
  22. *
  23. * @param Traversable $dirs Directories or a single path to search in
  24. * @param string $file The name of the class map file
  25. */
  26. public static function dump($dirs, $file)
  27. {
  28. $maps = array();
  29. foreach ($dirs as $dir) {
  30. $maps = array_merge($maps, static::createMap($dir));
  31. }
  32. file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
  33. }
  34. /**
  35. * Iterate over all files in the given directory searching for classes
  36. *
  37. * @param Iterator|string $dir The directory to search in or an iterator
  38. *
  39. * @return array A class map array
  40. */
  41. public static function createMap($dir)
  42. {
  43. if (is_string($dir)) {
  44. if (is_file($dir)) {
  45. $dir = array(new \SplFileInfo($dir));
  46. } else {
  47. $dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
  48. }
  49. }
  50. $map = array();
  51. foreach ($dir as $file) {
  52. if (!$file->isFile()) {
  53. continue;
  54. }
  55. $path = $file->getRealPath();
  56. if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
  57. continue;
  58. }
  59. $classes = self::findClasses($path);
  60. foreach ($classes as $class) {
  61. $map[$class] = $path;
  62. }
  63. }
  64. return $map;
  65. }
  66. /**
  67. * Extract the classes in the given file
  68. *
  69. * @param string $path The file to check
  70. *
  71. * @return array The found classes
  72. */
  73. private static function findClasses($path)
  74. {
  75. $contents = file_get_contents($path);
  76. try {
  77. if (!preg_match('{\b(?:class|interface|trait)\b}i', $contents)) {
  78. return array();
  79. }
  80. $tokens = token_get_all($contents);
  81. } catch (\Exception $e) {
  82. throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e);
  83. }
  84. $T_TRAIT = version_compare(PHP_VERSION, '5.4', '<') ? -1 : T_TRAIT;
  85. $classes = array();
  86. $namespace = '';
  87. for ($i = 0, $max = count($tokens); $i < $max; $i++) {
  88. $token = $tokens[$i];
  89. if (is_string($token)) {
  90. continue;
  91. }
  92. $class = '';
  93. switch ($token[0]) {
  94. case T_NAMESPACE:
  95. $namespace = '';
  96. // If there is a namespace, extract it
  97. while (($t = $tokens[++$i]) && is_array($t)) {
  98. if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) {
  99. $namespace .= $t[1];
  100. }
  101. }
  102. $namespace .= '\\';
  103. break;
  104. case T_CLASS:
  105. case T_INTERFACE:
  106. case $T_TRAIT:
  107. // Find the classname
  108. while (($t = $tokens[++$i]) && is_array($t)) {
  109. if (T_STRING === $t[0]) {
  110. $class .= $t[1];
  111. } elseif ($class !== '' && T_WHITESPACE == $t[0]) {
  112. break;
  113. }
  114. }
  115. $classes[] = ltrim($namespace . $class, '\\');
  116. break;
  117. default:
  118. break;
  119. }
  120. }
  121. return $classes;
  122. }
  123. }