PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/regularlabs/vendor/composer/ClassLoader.php

https://bitbucket.org/rippleau/nrm-org-au
PHP | 498 lines | 414 code | 20 blank | 64 comment | 16 complexity | b6ed4fb93e438e67ed677fe17abb1914 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, 0BSD, MIT, LGPL-2.1
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Autoload;
  12. /**
  13. * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
  14. *
  15. * $loader = new \Composer\Autoload\ClassLoader();
  16. *
  17. * // register classes with namespaces
  18. * $loader->add('Symfony\Component', __DIR__.'/component');
  19. * $loader->add('Symfony', __DIR__.'/framework');
  20. *
  21. * // activate the autoloader
  22. * $loader->register();
  23. *
  24. * // to enable searching the include path (eg. for PEAR packages)
  25. * $loader->setUseIncludePath(true);
  26. *
  27. * In this example, if you try to use a class in the Symfony\Component
  28. * namespace or one of its children (Symfony\Component\Console for instance),
  29. * the autoloader will first look for the class under the component/
  30. * directory, and it will then fallback to the framework/ directory if not
  31. * found before giving up.
  32. *
  33. * This class is loosely based on the Symfony UniversalClassLoader.
  34. *
  35. * @author Fabien Potencier <fabien@symfony.com>
  36. * @author Jordi Boggiano <j.boggiano@seld.be>
  37. * @see http://www.php-fig.org/psr/psr-0/
  38. * @see http://www.php-fig.org/psr/psr-4/
  39. */
  40. class ClassLoader
  41. {
  42. // PSR-4
  43. private $prefixLengthsPsr4 = [];
  44. private $prefixDirsPsr4 = [];
  45. private $fallbackDirsPsr4 = [];
  46. // PSR-0
  47. private $prefixesPsr0 = [];
  48. private $fallbackDirsPsr0 = [];
  49. private $useIncludePath = false;
  50. private $classMap = [];
  51. private $classMapAuthoritative = false;
  52. private $missingClasses = [];
  53. private $apcuPrefix;
  54. public function getPrefixes()
  55. {
  56. if ( ! empty($this->prefixesPsr0))
  57. {
  58. return call_user_func_array('array_merge', $this->prefixesPsr0);
  59. }
  60. return [];
  61. }
  62. public function getPrefixesPsr4()
  63. {
  64. return $this->prefixDirsPsr4;
  65. }
  66. public function getFallbackDirs()
  67. {
  68. return $this->fallbackDirsPsr0;
  69. }
  70. public function getFallbackDirsPsr4()
  71. {
  72. return $this->fallbackDirsPsr4;
  73. }
  74. public function getClassMap()
  75. {
  76. return $this->classMap;
  77. }
  78. /**
  79. * @param array $classMap Class to filename map
  80. */
  81. public function addClassMap(array $classMap)
  82. {
  83. if ($this->classMap)
  84. {
  85. $this->classMap = array_merge($this->classMap, $classMap);
  86. }
  87. else
  88. {
  89. $this->classMap = $classMap;
  90. }
  91. }
  92. /**
  93. * Registers a set of PSR-0 directories for a given prefix, either
  94. * appending or prepending to the ones previously set for this prefix.
  95. *
  96. * @param string $prefix The prefix
  97. * @param array|string $paths The PSR-0 root directories
  98. * @param bool $prepend Whether to prepend the directories
  99. */
  100. public function add($prefix, $paths, $prepend = false)
  101. {
  102. if ( ! $prefix)
  103. {
  104. if ($prepend)
  105. {
  106. $this->fallbackDirsPsr0 = array_merge(
  107. (array) $paths,
  108. $this->fallbackDirsPsr0
  109. );
  110. }
  111. else
  112. {
  113. $this->fallbackDirsPsr0 = array_merge(
  114. $this->fallbackDirsPsr0,
  115. (array) $paths
  116. );
  117. }
  118. return;
  119. }
  120. $first = $prefix[0];
  121. if ( ! isset($this->prefixesPsr0[$first][$prefix]))
  122. {
  123. $this->prefixesPsr0[$first][$prefix] = (array) $paths;
  124. return;
  125. }
  126. if ($prepend)
  127. {
  128. $this->prefixesPsr0[$first][$prefix] = array_merge(
  129. (array) $paths,
  130. $this->prefixesPsr0[$first][$prefix]
  131. );
  132. }
  133. else
  134. {
  135. $this->prefixesPsr0[$first][$prefix] = array_merge(
  136. $this->prefixesPsr0[$first][$prefix],
  137. (array) $paths
  138. );
  139. }
  140. }
  141. /**
  142. * Registers a set of PSR-4 directories for a given namespace, either
  143. * appending or prepending to the ones previously set for this namespace.
  144. *
  145. * @param string $prefix The prefix/namespace, with trailing '\\'
  146. * @param array|string $paths The PSR-4 base directories
  147. * @param bool $prepend Whether to prepend the directories
  148. *
  149. * @throws \InvalidArgumentException
  150. */
  151. public function addPsr4($prefix, $paths, $prepend = false)
  152. {
  153. if ( ! $prefix)
  154. {
  155. // Register directories for the root namespace.
  156. if ($prepend)
  157. {
  158. $this->fallbackDirsPsr4 = array_merge(
  159. (array) $paths,
  160. $this->fallbackDirsPsr4
  161. );
  162. }
  163. else
  164. {
  165. $this->fallbackDirsPsr4 = array_merge(
  166. $this->fallbackDirsPsr4,
  167. (array) $paths
  168. );
  169. }
  170. }
  171. elseif ( ! isset($this->prefixDirsPsr4[$prefix]))
  172. {
  173. // Register directories for a new namespace.
  174. $length = strlen($prefix);
  175. if ('\\' !== $prefix[$length - 1])
  176. {
  177. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  178. }
  179. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  180. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  181. }
  182. elseif ($prepend)
  183. {
  184. // Prepend directories for an already registered namespace.
  185. $this->prefixDirsPsr4[$prefix] = array_merge(
  186. (array) $paths,
  187. $this->prefixDirsPsr4[$prefix]
  188. );
  189. }
  190. else
  191. {
  192. // Append directories for an already registered namespace.
  193. $this->prefixDirsPsr4[$prefix] = array_merge(
  194. $this->prefixDirsPsr4[$prefix],
  195. (array) $paths
  196. );
  197. }
  198. }
  199. /**
  200. * Registers a set of PSR-0 directories for a given prefix,
  201. * replacing any others previously set for this prefix.
  202. *
  203. * @param string $prefix The prefix
  204. * @param array|string $paths The PSR-0 base directories
  205. */
  206. public function set($prefix, $paths)
  207. {
  208. if ( ! $prefix)
  209. {
  210. $this->fallbackDirsPsr0 = (array) $paths;
  211. }
  212. else
  213. {
  214. $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
  215. }
  216. }
  217. /**
  218. * Registers a set of PSR-4 directories for a given namespace,
  219. * replacing any others previously set for this namespace.
  220. *
  221. * @param string $prefix The prefix/namespace, with trailing '\\'
  222. * @param array|string $paths The PSR-4 base directories
  223. *
  224. * @throws \InvalidArgumentException
  225. */
  226. public function setPsr4($prefix, $paths)
  227. {
  228. if ( ! $prefix)
  229. {
  230. $this->fallbackDirsPsr4 = (array) $paths;
  231. }
  232. else
  233. {
  234. $length = strlen($prefix);
  235. if ('\\' !== $prefix[$length - 1])
  236. {
  237. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  238. }
  239. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  240. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  241. }
  242. }
  243. /**
  244. * Turns on searching the include path for class files.
  245. *
  246. * @param bool $useIncludePath
  247. */
  248. public function setUseIncludePath($useIncludePath)
  249. {
  250. $this->useIncludePath = $useIncludePath;
  251. }
  252. /**
  253. * Can be used to check if the autoloader uses the include path to check
  254. * for classes.
  255. *
  256. * @return bool
  257. */
  258. public function getUseIncludePath()
  259. {
  260. return $this->useIncludePath;
  261. }
  262. /**
  263. * Turns off searching the prefix and fallback directories for classes
  264. * that have not been registered with the class map.
  265. *
  266. * @param bool $classMapAuthoritative
  267. */
  268. public function setClassMapAuthoritative($classMapAuthoritative)
  269. {
  270. $this->classMapAuthoritative = $classMapAuthoritative;
  271. }
  272. /**
  273. * Should class lookup fail if not found in the current class map?
  274. *
  275. * @return bool
  276. */
  277. public function isClassMapAuthoritative()
  278. {
  279. return $this->classMapAuthoritative;
  280. }
  281. /**
  282. * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
  283. *
  284. * @param string|null $apcuPrefix
  285. */
  286. public function setApcuPrefix($apcuPrefix)
  287. {
  288. $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
  289. }
  290. /**
  291. * The APCu prefix in use, or null if APCu caching is not enabled.
  292. *
  293. * @return string|null
  294. */
  295. public function getApcuPrefix()
  296. {
  297. return $this->apcuPrefix;
  298. }
  299. /**
  300. * Registers this instance as an autoloader.
  301. *
  302. * @param bool $prepend Whether to prepend the autoloader or not
  303. */
  304. public function register($prepend = false)
  305. {
  306. spl_autoload_register([$this, 'loadClass'], true, $prepend);
  307. }
  308. /**
  309. * Unregisters this instance as an autoloader.
  310. */
  311. public function unregister()
  312. {
  313. spl_autoload_unregister([$this, 'loadClass']);
  314. }
  315. /**
  316. * Loads the given class or interface.
  317. *
  318. * @param string $class The name of the class
  319. *
  320. * @return bool|null True if loaded, null otherwise
  321. */
  322. public function loadClass($class)
  323. {
  324. if ($file = $this->findFile($class))
  325. {
  326. includeFile($file);
  327. return true;
  328. }
  329. }
  330. /**
  331. * Finds the path to the file where the class is defined.
  332. *
  333. * @param string $class The name of the class
  334. *
  335. * @return string|false The path if found, false otherwise
  336. */
  337. public function findFile($class)
  338. {
  339. // class map lookup
  340. if (isset($this->classMap[$class]))
  341. {
  342. return $this->classMap[$class];
  343. }
  344. if ($this->classMapAuthoritative || isset($this->missingClasses[$class]))
  345. {
  346. return false;
  347. }
  348. if (null !== $this->apcuPrefix)
  349. {
  350. $file = apcu_fetch($this->apcuPrefix . $class, $hit);
  351. if ($hit)
  352. {
  353. return $file;
  354. }
  355. }
  356. $file = $this->findFileWithExtension($class, '.php');
  357. // Search for Hack files if we are running on HHVM
  358. if (false === $file && defined('HHVM_VERSION'))
  359. {
  360. $file = $this->findFileWithExtension($class, '.hh');
  361. }
  362. if (null !== $this->apcuPrefix)
  363. {
  364. apcu_add($this->apcuPrefix . $class, $file);
  365. }
  366. if (false === $file)
  367. {
  368. // Remember that this class does not exist.
  369. $this->missingClasses[$class] = true;
  370. }
  371. return $file;
  372. }
  373. private function findFileWithExtension($class, $ext)
  374. {
  375. // PSR-4 lookup
  376. $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
  377. $first = $class[0];
  378. if (isset($this->prefixLengthsPsr4[$first]))
  379. {
  380. foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length)
  381. {
  382. if (0 === strpos($class, $prefix))
  383. {
  384. foreach ($this->prefixDirsPsr4[$prefix] as $dir)
  385. {
  386. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length)))
  387. {
  388. return $file;
  389. }
  390. }
  391. }
  392. }
  393. }
  394. // PSR-4 fallback dirs
  395. foreach ($this->fallbackDirsPsr4 as $dir)
  396. {
  397. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4))
  398. {
  399. return $file;
  400. }
  401. }
  402. // PSR-0 lookup
  403. if (false !== $pos = strrpos($class, '\\'))
  404. {
  405. // namespaced class name
  406. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  407. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
  408. }
  409. else
  410. {
  411. // PEAR-like class name
  412. $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
  413. }
  414. if (isset($this->prefixesPsr0[$first]))
  415. {
  416. foreach ($this->prefixesPsr0[$first] as $prefix => $dirs)
  417. {
  418. if (0 === strpos($class, $prefix))
  419. {
  420. foreach ($dirs as $dir)
  421. {
  422. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0))
  423. {
  424. return $file;
  425. }
  426. }
  427. }
  428. }
  429. }
  430. // PSR-0 fallback dirs
  431. foreach ($this->fallbackDirsPsr0 as $dir)
  432. {
  433. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0))
  434. {
  435. return $file;
  436. }
  437. }
  438. // PSR-0 include paths.
  439. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0))
  440. {
  441. return $file;
  442. }
  443. return false;
  444. }
  445. }
  446. /**
  447. * Scope isolated include.
  448. *
  449. * Prevents access to $this/self from included files.
  450. */
  451. function includeFile($file)
  452. {
  453. include $file;
  454. }