| 1: | <?php | 
| 2: |  | 
| 3: |  | 
| 4: |  | 
| 5: |  | 
| 6: |  | 
| 7: |  | 
| 8: |  | 
| 9: |  | 
| 10: |  | 
| 11: |  | 
| 12: |  | 
| 13: | namespace Composer\Autoload; | 
| 14: |  | 
| 15: |  | 
| 16: |  | 
| 17: |  | 
| 18: |  | 
| 19: |  | 
| 20: |  | 
| 21: |  | 
| 22: |  | 
| 23: |  | 
| 24: |  | 
| 25: |  | 
| 26: |  | 
| 27: |  | 
| 28: |  | 
| 29: |  | 
| 30: |  | 
| 31: |  | 
| 32: |  | 
| 33: |  | 
| 34: |  | 
| 35: |  | 
| 36: |  | 
| 37: |  | 
| 38: |  | 
| 39: |  | 
| 40: |  | 
| 41: |  | 
| 42: |  | 
| 43: | class ClassLoader | 
| 44: | { | 
| 45: |  | 
| 46: | private static $includeFile; | 
| 47: |  | 
| 48: |  | 
| 49: | private $vendorDir; | 
| 50: |  | 
| 51: |  | 
| 52: |  | 
| 53: |  | 
| 54: |  | 
| 55: | private $prefixLengthsPsr4 = array(); | 
| 56: |  | 
| 57: |  | 
| 58: |  | 
| 59: | private $prefixDirsPsr4 = array(); | 
| 60: |  | 
| 61: |  | 
| 62: |  | 
| 63: | private $fallbackDirsPsr4 = array(); | 
| 64: |  | 
| 65: |  | 
| 66: |  | 
| 67: |  | 
| 68: |  | 
| 69: |  | 
| 70: |  | 
| 71: |  | 
| 72: |  | 
| 73: | private $prefixesPsr0 = array(); | 
| 74: |  | 
| 75: |  | 
| 76: |  | 
| 77: | private $fallbackDirsPsr0 = array(); | 
| 78: |  | 
| 79: |  | 
| 80: | private $useIncludePath = false; | 
| 81: |  | 
| 82: |  | 
| 83: |  | 
| 84: |  | 
| 85: | private $classMap = array(); | 
| 86: |  | 
| 87: |  | 
| 88: | private $classMapAuthoritative = false; | 
| 89: |  | 
| 90: |  | 
| 91: |  | 
| 92: |  | 
| 93: | private $missingClasses = array(); | 
| 94: |  | 
| 95: |  | 
| 96: | private $apcuPrefix; | 
| 97: |  | 
| 98: |  | 
| 99: |  | 
| 100: |  | 
| 101: | private static $registeredLoaders = array(); | 
| 102: |  | 
| 103: |  | 
| 104: |  | 
| 105: |  | 
| 106: | public function __construct($vendorDir = null) | 
| 107: | { | 
| 108: | $this->vendorDir = $vendorDir; | 
| 109: | self::initializeIncludeClosure(); | 
| 110: | } | 
| 111: |  | 
| 112: |  | 
| 113: |  | 
| 114: |  | 
| 115: | public function getPrefixes() | 
| 116: | { | 
| 117: | if (!empty($this->prefixesPsr0)) { | 
| 118: | return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); | 
| 119: | } | 
| 120: |  | 
| 121: | return array(); | 
| 122: | } | 
| 123: |  | 
| 124: |  | 
| 125: |  | 
| 126: |  | 
| 127: | public function getPrefixesPsr4() | 
| 128: | { | 
| 129: | return $this->prefixDirsPsr4; | 
| 130: | } | 
| 131: |  | 
| 132: |  | 
| 133: |  | 
| 134: |  | 
| 135: | public function getFallbackDirs() | 
| 136: | { | 
| 137: | return $this->fallbackDirsPsr0; | 
| 138: | } | 
| 139: |  | 
| 140: |  | 
| 141: |  | 
| 142: |  | 
| 143: | public function getFallbackDirsPsr4() | 
| 144: | { | 
| 145: | return $this->fallbackDirsPsr4; | 
| 146: | } | 
| 147: |  | 
| 148: |  | 
| 149: |  | 
| 150: |  | 
| 151: | public function getClassMap() | 
| 152: | { | 
| 153: | return $this->classMap; | 
| 154: | } | 
| 155: |  | 
| 156: |  | 
| 157: |  | 
| 158: |  | 
| 159: |  | 
| 160: |  | 
| 161: | public function addClassMap(array $classMap) | 
| 162: | { | 
| 163: | if ($this->classMap) { | 
| 164: | $this->classMap = array_merge($this->classMap, $classMap); | 
| 165: | } else { | 
| 166: | $this->classMap = $classMap; | 
| 167: | } | 
| 168: | } | 
| 169: |  | 
| 170: |  | 
| 171: |  | 
| 172: |  | 
| 173: |  | 
| 174: |  | 
| 175: |  | 
| 176: |  | 
| 177: |  | 
| 178: |  | 
| 179: |  | 
| 180: | public function add($prefix, $paths, $prepend = false) | 
| 181: | { | 
| 182: | $paths = (array) $paths; | 
| 183: | if (!$prefix) { | 
| 184: | if ($prepend) { | 
| 185: | $this->fallbackDirsPsr0 = array_merge( | 
| 186: | $paths, | 
| 187: | $this->fallbackDirsPsr0 | 
| 188: | ); | 
| 189: | } else { | 
| 190: | $this->fallbackDirsPsr0 = array_merge( | 
| 191: | $this->fallbackDirsPsr0, | 
| 192: | $paths | 
| 193: | ); | 
| 194: | } | 
| 195: |  | 
| 196: | return; | 
| 197: | } | 
| 198: |  | 
| 199: | $first = $prefix[0]; | 
| 200: | if (!isset($this->prefixesPsr0[$first][$prefix])) { | 
| 201: | $this->prefixesPsr0[$first][$prefix] = $paths; | 
| 202: |  | 
| 203: | return; | 
| 204: | } | 
| 205: | if ($prepend) { | 
| 206: | $this->prefixesPsr0[$first][$prefix] = array_merge( | 
| 207: | $paths, | 
| 208: | $this->prefixesPsr0[$first][$prefix] | 
| 209: | ); | 
| 210: | } else { | 
| 211: | $this->prefixesPsr0[$first][$prefix] = array_merge( | 
| 212: | $this->prefixesPsr0[$first][$prefix], | 
| 213: | $paths | 
| 214: | ); | 
| 215: | } | 
| 216: | } | 
| 217: |  | 
| 218: |  | 
| 219: |  | 
| 220: |  | 
| 221: |  | 
| 222: |  | 
| 223: |  | 
| 224: |  | 
| 225: |  | 
| 226: |  | 
| 227: |  | 
| 228: |  | 
| 229: |  | 
| 230: | public function addPsr4($prefix, $paths, $prepend = false) | 
| 231: | { | 
| 232: | $paths = (array) $paths; | 
| 233: | if (!$prefix) { | 
| 234: |  | 
| 235: | if ($prepend) { | 
| 236: | $this->fallbackDirsPsr4 = array_merge( | 
| 237: | $paths, | 
| 238: | $this->fallbackDirsPsr4 | 
| 239: | ); | 
| 240: | } else { | 
| 241: | $this->fallbackDirsPsr4 = array_merge( | 
| 242: | $this->fallbackDirsPsr4, | 
| 243: | $paths | 
| 244: | ); | 
| 245: | } | 
| 246: | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { | 
| 247: |  | 
| 248: | $length = strlen($prefix); | 
| 249: | if ('\\' !== $prefix[$length - 1]) { | 
| 250: | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | 
| 251: | } | 
| 252: | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | 
| 253: | $this->prefixDirsPsr4[$prefix] = $paths; | 
| 254: | } elseif ($prepend) { | 
| 255: |  | 
| 256: | $this->prefixDirsPsr4[$prefix] = array_merge( | 
| 257: | $paths, | 
| 258: | $this->prefixDirsPsr4[$prefix] | 
| 259: | ); | 
| 260: | } else { | 
| 261: |  | 
| 262: | $this->prefixDirsPsr4[$prefix] = array_merge( | 
| 263: | $this->prefixDirsPsr4[$prefix], | 
| 264: | $paths | 
| 265: | ); | 
| 266: | } | 
| 267: | } | 
| 268: |  | 
| 269: |  | 
| 270: |  | 
| 271: |  | 
| 272: |  | 
| 273: |  | 
| 274: |  | 
| 275: |  | 
| 276: |  | 
| 277: |  | 
| 278: | public function set($prefix, $paths) | 
| 279: | { | 
| 280: | if (!$prefix) { | 
| 281: | $this->fallbackDirsPsr0 = (array) $paths; | 
| 282: | } else { | 
| 283: | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; | 
| 284: | } | 
| 285: | } | 
| 286: |  | 
| 287: |  | 
| 288: |  | 
| 289: |  | 
| 290: |  | 
| 291: |  | 
| 292: |  | 
| 293: |  | 
| 294: |  | 
| 295: |  | 
| 296: |  | 
| 297: |  | 
| 298: | public function setPsr4($prefix, $paths) | 
| 299: | { | 
| 300: | if (!$prefix) { | 
| 301: | $this->fallbackDirsPsr4 = (array) $paths; | 
| 302: | } else { | 
| 303: | $length = strlen($prefix); | 
| 304: | if ('\\' !== $prefix[$length - 1]) { | 
| 305: | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | 
| 306: | } | 
| 307: | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | 
| 308: | $this->prefixDirsPsr4[$prefix] = (array) $paths; | 
| 309: | } | 
| 310: | } | 
| 311: |  | 
| 312: |  | 
| 313: |  | 
| 314: |  | 
| 315: |  | 
| 316: |  | 
| 317: |  | 
| 318: |  | 
| 319: | public function setUseIncludePath($useIncludePath) | 
| 320: | { | 
| 321: | $this->useIncludePath = $useIncludePath; | 
| 322: | } | 
| 323: |  | 
| 324: |  | 
| 325: |  | 
| 326: |  | 
| 327: |  | 
| 328: |  | 
| 329: |  | 
| 330: | public function getUseIncludePath() | 
| 331: | { | 
| 332: | return $this->useIncludePath; | 
| 333: | } | 
| 334: |  | 
| 335: |  | 
| 336: |  | 
| 337: |  | 
| 338: |  | 
| 339: |  | 
| 340: |  | 
| 341: |  | 
| 342: |  | 
| 343: | public function setClassMapAuthoritative($classMapAuthoritative) | 
| 344: | { | 
| 345: | $this->classMapAuthoritative = $classMapAuthoritative; | 
| 346: | } | 
| 347: |  | 
| 348: |  | 
| 349: |  | 
| 350: |  | 
| 351: |  | 
| 352: |  | 
| 353: | public function isClassMapAuthoritative() | 
| 354: | { | 
| 355: | return $this->classMapAuthoritative; | 
| 356: | } | 
| 357: |  | 
| 358: |  | 
| 359: |  | 
| 360: |  | 
| 361: |  | 
| 362: |  | 
| 363: |  | 
| 364: |  | 
| 365: | public function setApcuPrefix($apcuPrefix) | 
| 366: | { | 
| 367: | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; | 
| 368: | } | 
| 369: |  | 
| 370: |  | 
| 371: |  | 
| 372: |  | 
| 373: |  | 
| 374: |  | 
| 375: | public function getApcuPrefix() | 
| 376: | { | 
| 377: | return $this->apcuPrefix; | 
| 378: | } | 
| 379: |  | 
| 380: |  | 
| 381: |  | 
| 382: |  | 
| 383: |  | 
| 384: |  | 
| 385: |  | 
| 386: |  | 
| 387: | public function register($prepend = false) | 
| 388: | { | 
| 389: | spl_autoload_register(array($this, 'loadClass'), true, $prepend); | 
| 390: |  | 
| 391: | if (null === $this->vendorDir) { | 
| 392: | return; | 
| 393: | } | 
| 394: |  | 
| 395: | if ($prepend) { | 
| 396: | self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; | 
| 397: | } else { | 
| 398: | unset(self::$registeredLoaders[$this->vendorDir]); | 
| 399: | self::$registeredLoaders[$this->vendorDir] = $this; | 
| 400: | } | 
| 401: | } | 
| 402: |  | 
| 403: |  | 
| 404: |  | 
| 405: |  | 
| 406: |  | 
| 407: |  | 
| 408: | public function unregister() | 
| 409: | { | 
| 410: | spl_autoload_unregister(array($this, 'loadClass')); | 
| 411: |  | 
| 412: | if (null !== $this->vendorDir) { | 
| 413: | unset(self::$registeredLoaders[$this->vendorDir]); | 
| 414: | } | 
| 415: | } | 
| 416: |  | 
| 417: |  | 
| 418: |  | 
| 419: |  | 
| 420: |  | 
| 421: |  | 
| 422: |  | 
| 423: | public function loadClass($class) | 
| 424: | { | 
| 425: | if ($file = $this->findFile($class)) { | 
| 426: | $includeFile = self::$includeFile; | 
| 427: | $includeFile($file); | 
| 428: |  | 
| 429: | return true; | 
| 430: | } | 
| 431: |  | 
| 432: | return null; | 
| 433: | } | 
| 434: |  | 
| 435: |  | 
| 436: |  | 
| 437: |  | 
| 438: |  | 
| 439: |  | 
| 440: |  | 
| 441: |  | 
| 442: | public function findFile($class) | 
| 443: | { | 
| 444: |  | 
| 445: | if (isset($this->classMap[$class])) { | 
| 446: | return $this->classMap[$class]; | 
| 447: | } | 
| 448: | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { | 
| 449: | return false; | 
| 450: | } | 
| 451: | if (null !== $this->apcuPrefix) { | 
| 452: | $file = apcu_fetch($this->apcuPrefix.$class, $hit); | 
| 453: | if ($hit) { | 
| 454: | return $file; | 
| 455: | } | 
| 456: | } | 
| 457: |  | 
| 458: | $file = $this->findFileWithExtension($class, '.php'); | 
| 459: |  | 
| 460: |  | 
| 461: | if (false === $file && defined('HHVM_VERSION')) { | 
| 462: | $file = $this->findFileWithExtension($class, '.hh'); | 
| 463: | } | 
| 464: |  | 
| 465: | if (null !== $this->apcuPrefix) { | 
| 466: | apcu_add($this->apcuPrefix.$class, $file); | 
| 467: | } | 
| 468: |  | 
| 469: | if (false === $file) { | 
| 470: |  | 
| 471: | $this->missingClasses[$class] = true; | 
| 472: | } | 
| 473: |  | 
| 474: | return $file; | 
| 475: | } | 
| 476: |  | 
| 477: |  | 
| 478: |  | 
| 479: |  | 
| 480: |  | 
| 481: |  | 
| 482: | public static function getRegisteredLoaders() | 
| 483: | { | 
| 484: | return self::$registeredLoaders; | 
| 485: | } | 
| 486: |  | 
| 487: |  | 
| 488: |  | 
| 489: |  | 
| 490: |  | 
| 491: |  | 
| 492: | private function findFileWithExtension($class, $ext) | 
| 493: | { | 
| 494: |  | 
| 495: | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; | 
| 496: |  | 
| 497: | $first = $class[0]; | 
| 498: | if (isset($this->prefixLengthsPsr4[$first])) { | 
| 499: | $subPath = $class; | 
| 500: | while (false !== $lastPos = strrpos($subPath, '\\')) { | 
| 501: | $subPath = substr($subPath, 0, $lastPos); | 
| 502: | $search = $subPath . '\\'; | 
| 503: | if (isset($this->prefixDirsPsr4[$search])) { | 
| 504: | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); | 
| 505: | foreach ($this->prefixDirsPsr4[$search] as $dir) { | 
| 506: | if (file_exists($file = $dir . $pathEnd)) { | 
| 507: | return $file; | 
| 508: | } | 
| 509: | } | 
| 510: | } | 
| 511: | } | 
| 512: | } | 
| 513: |  | 
| 514: |  | 
| 515: | foreach ($this->fallbackDirsPsr4 as $dir) { | 
| 516: | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { | 
| 517: | return $file; | 
| 518: | } | 
| 519: | } | 
| 520: |  | 
| 521: |  | 
| 522: | if (false !== $pos = strrpos($class, '\\')) { | 
| 523: |  | 
| 524: | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) | 
| 525: | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); | 
| 526: | } else { | 
| 527: |  | 
| 528: | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; | 
| 529: | } | 
| 530: |  | 
| 531: | if (isset($this->prefixesPsr0[$first])) { | 
| 532: | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { | 
| 533: | if (0 === strpos($class, $prefix)) { | 
| 534: | foreach ($dirs as $dir) { | 
| 535: | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | 
| 536: | return $file; | 
| 537: | } | 
| 538: | } | 
| 539: | } | 
| 540: | } | 
| 541: | } | 
| 542: |  | 
| 543: |  | 
| 544: | foreach ($this->fallbackDirsPsr0 as $dir) { | 
| 545: | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | 
| 546: | return $file; | 
| 547: | } | 
| 548: | } | 
| 549: |  | 
| 550: |  | 
| 551: | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | 
| 552: | return $file; | 
| 553: | } | 
| 554: |  | 
| 555: | return false; | 
| 556: | } | 
| 557: |  | 
| 558: |  | 
| 559: |  | 
| 560: |  | 
| 561: | private static function initializeIncludeClosure() | 
| 562: | { | 
| 563: | if (self::$includeFile !== null) { | 
| 564: | return; | 
| 565: | } | 
| 566: |  | 
| 567: |  | 
| 568: |  | 
| 569: |  | 
| 570: |  | 
| 571: |  | 
| 572: |  | 
| 573: |  | 
| 574: |  | 
| 575: | self::$includeFile = \Closure::bind(static function($file) { | 
| 576: | include $file; | 
| 577: | }, null, null); | 
| 578: | } | 
| 579: | } | 
| 580: |  |