AnnotationRegistry.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?php
  2. namespace Doctrine\Common\Annotations;
  3. use function array_key_exists;
  4. use function array_merge;
  5. use function class_exists;
  6. use function in_array;
  7. use function is_file;
  8. use function str_replace;
  9. use function stream_resolve_include_path;
  10. use function strpos;
  11. use const DIRECTORY_SEPARATOR;
  12. final class AnnotationRegistry
  13. {
  14. /**
  15. * A map of namespaces to use for autoloading purposes based on a PSR-0 convention.
  16. *
  17. * Contains the namespace as key and an array of directories as value. If the value is NULL
  18. * the include path is used for checking for the corresponding file.
  19. *
  20. * This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own.
  21. *
  22. * @var string[][]|string[]|null[]
  23. */
  24. private static $autoloadNamespaces = [];
  25. /**
  26. * A map of autoloader callables.
  27. *
  28. * @var callable[]
  29. */
  30. private static $loaders = [];
  31. /**
  32. * An array of classes which cannot be found
  33. *
  34. * @var null[] indexed by class name
  35. */
  36. private static $failedToAutoload = [];
  37. /**
  38. * Whenever registerFile() was used. Disables use of standard autoloader.
  39. *
  40. * @var bool
  41. */
  42. private static $registerFileUsed = false;
  43. public static function reset(): void
  44. {
  45. self::$autoloadNamespaces = [];
  46. self::$loaders = [];
  47. self::$failedToAutoload = [];
  48. self::$registerFileUsed = false;
  49. }
  50. /**
  51. * Registers file.
  52. *
  53. * @deprecated This method is deprecated and will be removed in
  54. * doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
  55. */
  56. public static function registerFile(string $file): void
  57. {
  58. self::$registerFileUsed = true;
  59. require_once $file;
  60. }
  61. /**
  62. * Adds a namespace with one or many directories to look for files or null for the include path.
  63. *
  64. * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
  65. *
  66. * @deprecated This method is deprecated and will be removed in
  67. * doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
  68. *
  69. * @phpstan-param string|list<string>|null $dirs
  70. */
  71. public static function registerAutoloadNamespace(string $namespace, $dirs = null): void
  72. {
  73. self::$autoloadNamespaces[$namespace] = $dirs;
  74. }
  75. /**
  76. * Registers multiple namespaces.
  77. *
  78. * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
  79. *
  80. * @deprecated This method is deprecated and will be removed in
  81. * doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
  82. *
  83. * @param string[][]|string[]|null[] $namespaces indexed by namespace name
  84. */
  85. public static function registerAutoloadNamespaces(array $namespaces): void
  86. {
  87. self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces);
  88. }
  89. /**
  90. * Registers an autoloading callable for annotations, much like spl_autoload_register().
  91. *
  92. * NOTE: These class loaders HAVE to be silent when a class was not found!
  93. * IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class.
  94. *
  95. * @deprecated This method is deprecated and will be removed in
  96. * doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
  97. */
  98. public static function registerLoader(callable $callable): void
  99. {
  100. // Reset our static cache now that we have a new loader to work with
  101. self::$failedToAutoload = [];
  102. self::$loaders[] = $callable;
  103. }
  104. /**
  105. * Registers an autoloading callable for annotations, if it is not already registered
  106. *
  107. * @deprecated This method is deprecated and will be removed in
  108. * doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
  109. */
  110. public static function registerUniqueLoader(callable $callable): void
  111. {
  112. if (in_array($callable, self::$loaders, true)) {
  113. return;
  114. }
  115. self::registerLoader($callable);
  116. }
  117. /**
  118. * Autoloads an annotation class silently.
  119. */
  120. public static function loadAnnotationClass(string $class): bool
  121. {
  122. if (class_exists($class, false)) {
  123. return true;
  124. }
  125. if (array_key_exists($class, self::$failedToAutoload)) {
  126. return false;
  127. }
  128. foreach (self::$autoloadNamespaces as $namespace => $dirs) {
  129. if (strpos($class, $namespace) !== 0) {
  130. continue;
  131. }
  132. $file = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
  133. if ($dirs === null) {
  134. $path = stream_resolve_include_path($file);
  135. if ($path) {
  136. require $path;
  137. return true;
  138. }
  139. } else {
  140. foreach ((array) $dirs as $dir) {
  141. if (is_file($dir . DIRECTORY_SEPARATOR . $file)) {
  142. require $dir . DIRECTORY_SEPARATOR . $file;
  143. return true;
  144. }
  145. }
  146. }
  147. }
  148. foreach (self::$loaders as $loader) {
  149. if ($loader($class) === true) {
  150. return true;
  151. }
  152. }
  153. if (
  154. self::$loaders === [] &&
  155. self::$autoloadNamespaces === [] &&
  156. self::$registerFileUsed === false &&
  157. class_exists($class)
  158. ) {
  159. return true;
  160. }
  161. self::$failedToAutoload[$class] = null;
  162. return false;
  163. }
  164. }