annotate vendor/squizlabs/php_codesniffer/autoload.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@17 1 <?php
Chris@17 2 /**
Chris@17 3 * Autoloads files for PHP_CodeSniffer and tracks what has been loaded.
Chris@17 4 *
Chris@17 5 * Due to different namespaces being used for custom coding standards,
Chris@17 6 * the autoloader keeps track of what class is loaded after a file is included,
Chris@17 7 * even if the file is ultimately included by another autoloader (such as composer).
Chris@17 8 *
Chris@17 9 * This allows PHP_CodeSniffer to request the class name after loading a class
Chris@17 10 * when it only knows the filename, without having to parse the file to find it.
Chris@17 11 *
Chris@17 12 * @author Greg Sherwood <gsherwood@squiz.net>
Chris@17 13 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
Chris@17 14 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@17 15 */
Chris@17 16
Chris@17 17 namespace PHP_CodeSniffer;
Chris@17 18
Chris@17 19 if (class_exists('PHP_CodeSniffer\Autoload', false) === false) {
Chris@17 20 class Autoload
Chris@17 21 {
Chris@17 22
Chris@17 23 /**
Chris@17 24 * The composer autoloader.
Chris@17 25 *
Chris@18 26 * @var \Composer\Autoload\ClassLoader
Chris@17 27 */
Chris@17 28 private static $composerAutoloader = null;
Chris@17 29
Chris@17 30 /**
Chris@17 31 * A mapping of file names to class names.
Chris@17 32 *
Chris@17 33 * @var array<string, string>
Chris@17 34 */
Chris@17 35 private static $loadedClasses = [];
Chris@17 36
Chris@17 37 /**
Chris@17 38 * A mapping of class names to file names.
Chris@17 39 *
Chris@17 40 * @var array<string, string>
Chris@17 41 */
Chris@17 42 private static $loadedFiles = [];
Chris@17 43
Chris@17 44 /**
Chris@17 45 * A list of additional directories to search during autoloading.
Chris@17 46 *
Chris@17 47 * This is typically a list of coding standard directories.
Chris@17 48 *
Chris@17 49 * @var string[]
Chris@17 50 */
Chris@17 51 private static $searchPaths = [];
Chris@17 52
Chris@17 53
Chris@17 54 /**
Chris@17 55 * Loads a class.
Chris@17 56 *
Chris@17 57 * This method only loads classes that exist in the PHP_CodeSniffer namespace.
Chris@17 58 * All other classes are ignored and loaded by subsequent autoloaders.
Chris@17 59 *
Chris@17 60 * @param string $class The name of the class to load.
Chris@17 61 *
Chris@17 62 * @return bool
Chris@17 63 */
Chris@17 64 public static function load($class)
Chris@17 65 {
Chris@17 66 // Include the composer autoloader if there is one, but re-register it
Chris@17 67 // so this autoloader runs before the composer one as we need to include
Chris@17 68 // all files so we can figure out what the class/interface/trait name is.
Chris@17 69 if (self::$composerAutoloader === null) {
Chris@17 70 // Make sure we don't try to load any of Composer's classes
Chris@17 71 // while the autoloader is being setup.
Chris@17 72 if (strpos($class, 'Composer\\') === 0) {
Chris@17 73 return;
Chris@17 74 }
Chris@17 75
Chris@17 76 if (strpos(__DIR__, 'phar://') !== 0
Chris@17 77 && file_exists(__DIR__.'/../../autoload.php') === true
Chris@17 78 ) {
Chris@17 79 self::$composerAutoloader = include __DIR__.'/../../autoload.php';
Chris@17 80 if (self::$composerAutoloader instanceof \Composer\Autoload\ClassLoader) {
Chris@17 81 self::$composerAutoloader->unregister();
Chris@17 82 self::$composerAutoloader->register();
Chris@17 83 } else {
Chris@17 84 // Something went wrong, so keep going without the autoloader
Chris@17 85 // although namespaced sniffs might error.
Chris@17 86 self::$composerAutoloader = false;
Chris@17 87 }
Chris@17 88 } else {
Chris@17 89 self::$composerAutoloader = false;
Chris@17 90 }
Chris@17 91 }//end if
Chris@17 92
Chris@17 93 $ds = DIRECTORY_SEPARATOR;
Chris@17 94 $path = false;
Chris@17 95
Chris@17 96 if (substr($class, 0, 16) === 'PHP_CodeSniffer\\') {
Chris@17 97 if (substr($class, 0, 22) === 'PHP_CodeSniffer\Tests\\') {
Chris@17 98 $isInstalled = !is_dir(__DIR__.$ds.'tests');
Chris@17 99 if ($isInstalled === false) {
Chris@17 100 $path = __DIR__.$ds.'tests';
Chris@17 101 } else {
Chris@17 102 $path = '@test_dir@'.$ds.'PHP_CodeSniffer'.$ds.'CodeSniffer';
Chris@17 103 }
Chris@17 104
Chris@17 105 $path .= $ds.substr(str_replace('\\', $ds, $class), 22).'.php';
Chris@17 106 } else {
Chris@17 107 $path = __DIR__.$ds.'src'.$ds.substr(str_replace('\\', $ds, $class), 16).'.php';
Chris@17 108 }
Chris@17 109 }
Chris@17 110
Chris@17 111 // See if the composer autoloader knows where the class is.
Chris@17 112 if ($path === false && self::$composerAutoloader !== false) {
Chris@17 113 $path = self::$composerAutoloader->findFile($class);
Chris@17 114 }
Chris@17 115
Chris@17 116 // See if the class is inside one of our alternate search paths.
Chris@17 117 if ($path === false) {
Chris@17 118 foreach (self::$searchPaths as $searchPath => $nsPrefix) {
Chris@17 119 $className = $class;
Chris@17 120 if ($nsPrefix !== '' && substr($class, 0, strlen($nsPrefix)) === $nsPrefix) {
Chris@17 121 $className = substr($class, (strlen($nsPrefix) + 1));
Chris@17 122 }
Chris@17 123
Chris@17 124 $path = $searchPath.$ds.str_replace('\\', $ds, $className).'.php';
Chris@17 125 if (is_file($path) === true) {
Chris@17 126 break;
Chris@17 127 }
Chris@17 128
Chris@17 129 $path = false;
Chris@17 130 }
Chris@17 131 }
Chris@17 132
Chris@17 133 if ($path !== false && is_file($path) === true) {
Chris@17 134 self::loadFile($path);
Chris@17 135 return true;
Chris@17 136 }
Chris@17 137
Chris@17 138 return false;
Chris@17 139
Chris@17 140 }//end load()
Chris@17 141
Chris@17 142
Chris@17 143 /**
Chris@17 144 * Includes a file and tracks what class or interface was loaded as a result.
Chris@17 145 *
Chris@17 146 * @param string $path The path of the file to load.
Chris@17 147 *
Chris@17 148 * @return string The fully qualified name of the class in the loaded file.
Chris@17 149 */
Chris@17 150 public static function loadFile($path)
Chris@17 151 {
Chris@17 152 if (strpos(__DIR__, 'phar://') !== 0) {
Chris@17 153 $path = realpath($path);
Chris@17 154 if ($path === false) {
Chris@17 155 return false;
Chris@17 156 }
Chris@17 157 }
Chris@17 158
Chris@17 159 if (isset(self::$loadedClasses[$path]) === true) {
Chris@17 160 return self::$loadedClasses[$path];
Chris@17 161 }
Chris@17 162
Chris@17 163 $classes = get_declared_classes();
Chris@17 164 $interfaces = get_declared_interfaces();
Chris@17 165 $traits = get_declared_traits();
Chris@17 166
Chris@17 167 include $path;
Chris@17 168
Chris@17 169 $className = null;
Chris@17 170 $newClasses = array_reverse(array_diff(get_declared_classes(), $classes));
Chris@17 171 foreach ($newClasses as $name) {
Chris@17 172 if (isset(self::$loadedFiles[$name]) === false) {
Chris@17 173 $className = $name;
Chris@17 174 break;
Chris@17 175 }
Chris@17 176 }
Chris@17 177
Chris@17 178 if ($className === null) {
Chris@17 179 $newClasses = array_reverse(array_diff(get_declared_interfaces(), $interfaces));
Chris@17 180 foreach ($newClasses as $name) {
Chris@17 181 if (isset(self::$loadedFiles[$name]) === false) {
Chris@17 182 $className = $name;
Chris@17 183 break;
Chris@17 184 }
Chris@17 185 }
Chris@17 186 }
Chris@17 187
Chris@17 188 if ($className === null) {
Chris@17 189 $newClasses = array_reverse(array_diff(get_declared_traits(), $traits));
Chris@17 190 foreach ($newClasses as $name) {
Chris@17 191 if (isset(self::$loadedFiles[$name]) === false) {
Chris@17 192 $className = $name;
Chris@17 193 break;
Chris@17 194 }
Chris@17 195 }
Chris@17 196 }
Chris@17 197
Chris@17 198 self::$loadedClasses[$path] = $className;
Chris@17 199 self::$loadedFiles[$className] = $path;
Chris@17 200 return self::$loadedClasses[$path];
Chris@17 201
Chris@17 202 }//end loadFile()
Chris@17 203
Chris@17 204
Chris@17 205 /**
Chris@17 206 * Adds a directory to search during autoloading.
Chris@17 207 *
Chris@17 208 * @param string $path The path to the directory to search.
Chris@17 209 * @param string $nsPrefix The namespace prefix used by files under this path.
Chris@17 210 *
Chris@17 211 * @return void
Chris@17 212 */
Chris@17 213 public static function addSearchPath($path, $nsPrefix='')
Chris@17 214 {
Chris@17 215 self::$searchPaths[$path] = rtrim(trim((string) $nsPrefix), '\\');
Chris@17 216
Chris@17 217 }//end addSearchPath()
Chris@17 218
Chris@17 219
Chris@17 220 /**
Chris@17 221 * Retrieve the namespaces and paths registered by external standards.
Chris@17 222 *
Chris@17 223 * @return array
Chris@17 224 */
Chris@17 225 public static function getSearchPaths()
Chris@17 226 {
Chris@17 227 return self::$searchPaths;
Chris@17 228
Chris@17 229 }//end getSearchPaths()
Chris@17 230
Chris@17 231
Chris@17 232 /**
Chris@17 233 * Gets the class name for the given file path.
Chris@17 234 *
Chris@17 235 * @param string $path The name of the file.
Chris@17 236 *
Chris@17 237 * @throws \Exception If the file path has not been loaded.
Chris@17 238 * @return string
Chris@17 239 */
Chris@17 240 public static function getLoadedClassName($path)
Chris@17 241 {
Chris@17 242 if (isset(self::$loadedClasses[$path]) === false) {
Chris@17 243 throw new \Exception("Cannot get class name for $path; file has not been included");
Chris@17 244 }
Chris@17 245
Chris@17 246 return self::$loadedClasses[$path];
Chris@17 247
Chris@17 248 }//end getLoadedClassName()
Chris@17 249
Chris@17 250
Chris@17 251 /**
Chris@17 252 * Gets the file path for the given class name.
Chris@17 253 *
Chris@17 254 * @param string $class The name of the class.
Chris@17 255 *
Chris@17 256 * @throws \Exception If the class name has not been loaded
Chris@17 257 * @return string
Chris@17 258 */
Chris@17 259 public static function getLoadedFileName($class)
Chris@17 260 {
Chris@17 261 if (isset(self::$loadedFiles[$class]) === false) {
Chris@17 262 throw new \Exception("Cannot get file name for $class; class has not been included");
Chris@17 263 }
Chris@17 264
Chris@17 265 return self::$loadedFiles[$class];
Chris@17 266
Chris@17 267 }//end getLoadedFileName()
Chris@17 268
Chris@17 269
Chris@17 270 /**
Chris@17 271 * Gets the mapping of file names to class names.
Chris@17 272 *
Chris@17 273 * @return array<string, string>
Chris@17 274 */
Chris@17 275 public static function getLoadedClasses()
Chris@17 276 {
Chris@17 277 return self::$loadedClasses;
Chris@17 278
Chris@17 279 }//end getLoadedClasses()
Chris@17 280
Chris@17 281
Chris@17 282 /**
Chris@17 283 * Gets the mapping of class names to file names.
Chris@17 284 *
Chris@17 285 * @return array<string, string>
Chris@17 286 */
Chris@17 287 public static function getLoadedFiles()
Chris@17 288 {
Chris@17 289 return self::$loadedFiles;
Chris@17 290
Chris@17 291 }//end getLoadedFiles()
Chris@17 292
Chris@17 293
Chris@17 294 }//end class
Chris@17 295
Chris@17 296 // Register the autoloader before any existing autoloaders to ensure
Chris@17 297 // it gets a chance to hear about every autoload request, and record
Chris@17 298 // the file and class name for it.
Chris@17 299 spl_autoload_register(__NAMESPACE__.'\Autoload::load', true, true);
Chris@17 300 }//end if