Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

ClassLoader.php 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  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 https://www.php-fig.org/psr/psr-0/
  38. * @see https://www.php-fig.org/psr/psr-4/
  39. */
  40. class ClassLoader
  41. {
  42. /** @var ?string */
  43. private $vendorDir;
  44. // PSR-4
  45. /**
  46. * @var array[]
  47. * @psalm-var array<string, array<string, int>>
  48. */
  49. private $prefixLengthsPsr4 = array();
  50. /**
  51. * @var array[]
  52. * @psalm-var array<string, array<int, string>>
  53. */
  54. private $prefixDirsPsr4 = array();
  55. /**
  56. * @var array[]
  57. * @psalm-var array<string, string>
  58. */
  59. private $fallbackDirsPsr4 = array();
  60. // PSR-0
  61. /**
  62. * @var array[]
  63. * @psalm-var array<string, array<string, string[]>>
  64. */
  65. private $prefixesPsr0 = array();
  66. /**
  67. * @var array[]
  68. * @psalm-var array<string, string>
  69. */
  70. private $fallbackDirsPsr0 = array();
  71. /** @var bool */
  72. private $useIncludePath = false;
  73. /**
  74. * @var string[]
  75. * @psalm-var array<string, string>
  76. */
  77. private $classMap = array();
  78. /** @var bool */
  79. private $classMapAuthoritative = false;
  80. /**
  81. * @var bool[]
  82. * @psalm-var array<string, bool>
  83. */
  84. private $missingClasses = array();
  85. /** @var ?string */
  86. private $apcuPrefix;
  87. /**
  88. * @var self[]
  89. */
  90. private static $registeredLoaders = array();
  91. /**
  92. * @param ?string $vendorDir
  93. */
  94. public function __construct($vendorDir = null)
  95. {
  96. $this->vendorDir = $vendorDir;
  97. }
  98. /**
  99. * @return string[]
  100. */
  101. public function getPrefixes()
  102. {
  103. if (!empty($this->prefixesPsr0)) {
  104. return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
  105. }
  106. return array();
  107. }
  108. /**
  109. * @return array[]
  110. * @psalm-return array<string, array<int, string>>
  111. */
  112. public function getPrefixesPsr4()
  113. {
  114. return $this->prefixDirsPsr4;
  115. }
  116. /**
  117. * @return array[]
  118. * @psalm-return array<string, string>
  119. */
  120. public function getFallbackDirs()
  121. {
  122. return $this->fallbackDirsPsr0;
  123. }
  124. /**
  125. * @return array[]
  126. * @psalm-return array<string, string>
  127. */
  128. public function getFallbackDirsPsr4()
  129. {
  130. return $this->fallbackDirsPsr4;
  131. }
  132. /**
  133. * @return string[] Array of classname => path
  134. * @psalm-return array<string, string>
  135. */
  136. public function getClassMap()
  137. {
  138. return $this->classMap;
  139. }
  140. /**
  141. * @param string[] $classMap Class to filename map
  142. * @psalm-param array<string, string> $classMap
  143. *
  144. * @return void
  145. */
  146. public function addClassMap(array $classMap)
  147. {
  148. if ($this->classMap) {
  149. $this->classMap = array_merge($this->classMap, $classMap);
  150. } else {
  151. $this->classMap = $classMap;
  152. }
  153. }
  154. /**
  155. * Registers a set of PSR-0 directories for a given prefix, either
  156. * appending or prepending to the ones previously set for this prefix.
  157. *
  158. * @param string $prefix The prefix
  159. * @param string[]|string $paths The PSR-0 root directories
  160. * @param bool $prepend Whether to prepend the directories
  161. *
  162. * @return void
  163. */
  164. public function add($prefix, $paths, $prepend = false)
  165. {
  166. if (!$prefix) {
  167. if ($prepend) {
  168. $this->fallbackDirsPsr0 = array_merge(
  169. (array) $paths,
  170. $this->fallbackDirsPsr0
  171. );
  172. } else {
  173. $this->fallbackDirsPsr0 = array_merge(
  174. $this->fallbackDirsPsr0,
  175. (array) $paths
  176. );
  177. }
  178. return;
  179. }
  180. $first = $prefix[0];
  181. if (!isset($this->prefixesPsr0[$first][$prefix])) {
  182. $this->prefixesPsr0[$first][$prefix] = (array) $paths;
  183. return;
  184. }
  185. if ($prepend) {
  186. $this->prefixesPsr0[$first][$prefix] = array_merge(
  187. (array) $paths,
  188. $this->prefixesPsr0[$first][$prefix]
  189. );
  190. } else {
  191. $this->prefixesPsr0[$first][$prefix] = array_merge(
  192. $this->prefixesPsr0[$first][$prefix],
  193. (array) $paths
  194. );
  195. }
  196. }
  197. /**
  198. * Registers a set of PSR-4 directories for a given namespace, either
  199. * appending or prepending to the ones previously set for this namespace.
  200. *
  201. * @param string $prefix The prefix/namespace, with trailing '\\'
  202. * @param string[]|string $paths The PSR-4 base directories
  203. * @param bool $prepend Whether to prepend the directories
  204. *
  205. * @throws \InvalidArgumentException
  206. *
  207. * @return void
  208. */
  209. public function addPsr4($prefix, $paths, $prepend = false)
  210. {
  211. if (!$prefix) {
  212. // Register directories for the root namespace.
  213. if ($prepend) {
  214. $this->fallbackDirsPsr4 = array_merge(
  215. (array) $paths,
  216. $this->fallbackDirsPsr4
  217. );
  218. } else {
  219. $this->fallbackDirsPsr4 = array_merge(
  220. $this->fallbackDirsPsr4,
  221. (array) $paths
  222. );
  223. }
  224. } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
  225. // Register directories for a new namespace.
  226. $length = strlen($prefix);
  227. if ('\\' !== $prefix[$length - 1]) {
  228. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  229. }
  230. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  231. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  232. } elseif ($prepend) {
  233. // Prepend directories for an already registered namespace.
  234. $this->prefixDirsPsr4[$prefix] = array_merge(
  235. (array) $paths,
  236. $this->prefixDirsPsr4[$prefix]
  237. );
  238. } else {
  239. // Append directories for an already registered namespace.
  240. $this->prefixDirsPsr4[$prefix] = array_merge(
  241. $this->prefixDirsPsr4[$prefix],
  242. (array) $paths
  243. );
  244. }
  245. }
  246. /**
  247. * Registers a set of PSR-0 directories for a given prefix,
  248. * replacing any others previously set for this prefix.
  249. *
  250. * @param string $prefix The prefix
  251. * @param string[]|string $paths The PSR-0 base directories
  252. *
  253. * @return void
  254. */
  255. public function set($prefix, $paths)
  256. {
  257. if (!$prefix) {
  258. $this->fallbackDirsPsr0 = (array) $paths;
  259. } else {
  260. $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
  261. }
  262. }
  263. /**
  264. * Registers a set of PSR-4 directories for a given namespace,
  265. * replacing any others previously set for this namespace.
  266. *
  267. * @param string $prefix The prefix/namespace, with trailing '\\'
  268. * @param string[]|string $paths The PSR-4 base directories
  269. *
  270. * @throws \InvalidArgumentException
  271. *
  272. * @return void
  273. */
  274. public function setPsr4($prefix, $paths)
  275. {
  276. if (!$prefix) {
  277. $this->fallbackDirsPsr4 = (array) $paths;
  278. } else {
  279. $length = strlen($prefix);
  280. if ('\\' !== $prefix[$length - 1]) {
  281. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  282. }
  283. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  284. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  285. }
  286. }
  287. /**
  288. * Turns on searching the include path for class files.
  289. *
  290. * @param bool $useIncludePath
  291. *
  292. * @return void
  293. */
  294. public function setUseIncludePath($useIncludePath)
  295. {
  296. $this->useIncludePath = $useIncludePath;
  297. }
  298. /**
  299. * Can be used to check if the autoloader uses the include path to check
  300. * for classes.
  301. *
  302. * @return bool
  303. */
  304. public function getUseIncludePath()
  305. {
  306. return $this->useIncludePath;
  307. }
  308. /**
  309. * Turns off searching the prefix and fallback directories for classes
  310. * that have not been registered with the class map.
  311. *
  312. * @param bool $classMapAuthoritative
  313. *
  314. * @return void
  315. */
  316. public function setClassMapAuthoritative($classMapAuthoritative)
  317. {
  318. $this->classMapAuthoritative = $classMapAuthoritative;
  319. }
  320. /**
  321. * Should class lookup fail if not found in the current class map?
  322. *
  323. * @return bool
  324. */
  325. public function isClassMapAuthoritative()
  326. {
  327. return $this->classMapAuthoritative;
  328. }
  329. /**
  330. * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
  331. *
  332. * @param string|null $apcuPrefix
  333. *
  334. * @return void
  335. */
  336. public function setApcuPrefix($apcuPrefix)
  337. {
  338. $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
  339. }
  340. /**
  341. * The APCu prefix in use, or null if APCu caching is not enabled.
  342. *
  343. * @return string|null
  344. */
  345. public function getApcuPrefix()
  346. {
  347. return $this->apcuPrefix;
  348. }
  349. /**
  350. * Registers this instance as an autoloader.
  351. *
  352. * @param bool $prepend Whether to prepend the autoloader or not
  353. *
  354. * @return void
  355. */
  356. public function register($prepend = false)
  357. {
  358. spl_autoload_register(array($this, 'loadClass'), true, $prepend);
  359. if (null === $this->vendorDir) {
  360. return;
  361. }
  362. if ($prepend) {
  363. self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
  364. } else {
  365. unset(self::$registeredLoaders[$this->vendorDir]);
  366. self::$registeredLoaders[$this->vendorDir] = $this;
  367. }
  368. }
  369. /**
  370. * Unregisters this instance as an autoloader.
  371. *
  372. * @return void
  373. */
  374. public function unregister()
  375. {
  376. spl_autoload_unregister(array($this, 'loadClass'));
  377. if (null !== $this->vendorDir) {
  378. unset(self::$registeredLoaders[$this->vendorDir]);
  379. }
  380. }
  381. /**
  382. * Loads the given class or interface.
  383. *
  384. * @param string $class The name of the class
  385. * @return true|null True if loaded, null otherwise
  386. */
  387. public function loadClass($class)
  388. {
  389. if ($file = $this->findFile($class)) {
  390. includeFile($file);
  391. return true;
  392. }
  393. return null;
  394. }
  395. /**
  396. * Finds the path to the file where the class is defined.
  397. *
  398. * @param string $class The name of the class
  399. *
  400. * @return string|false The path if found, false otherwise
  401. */
  402. public function findFile($class)
  403. {
  404. // class map lookup
  405. if (isset($this->classMap[$class])) {
  406. return $this->classMap[$class];
  407. }
  408. if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
  409. return false;
  410. }
  411. if (null !== $this->apcuPrefix) {
  412. $file = apcu_fetch($this->apcuPrefix.$class, $hit);
  413. if ($hit) {
  414. return $file;
  415. }
  416. }
  417. $file = $this->findFileWithExtension($class, '.php');
  418. // Search for Hack files if we are running on HHVM
  419. if (false === $file && defined('HHVM_VERSION')) {
  420. $file = $this->findFileWithExtension($class, '.hh');
  421. }
  422. if (null !== $this->apcuPrefix) {
  423. apcu_add($this->apcuPrefix.$class, $file);
  424. }
  425. if (false === $file) {
  426. // Remember that this class does not exist.
  427. $this->missingClasses[$class] = true;
  428. }
  429. return $file;
  430. }
  431. /**
  432. * Returns the currently registered loaders indexed by their corresponding vendor directories.
  433. *
  434. * @return self[]
  435. */
  436. public static function getRegisteredLoaders()
  437. {
  438. return self::$registeredLoaders;
  439. }
  440. /**
  441. * @param string $class
  442. * @param string $ext
  443. * @return string|false
  444. */
  445. private function findFileWithExtension($class, $ext)
  446. {
  447. // PSR-4 lookup
  448. $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
  449. $first = $class[0];
  450. if (isset($this->prefixLengthsPsr4[$first])) {
  451. $subPath = $class;
  452. while (false !== $lastPos = strrpos($subPath, '\\')) {
  453. $subPath = substr($subPath, 0, $lastPos);
  454. $search = $subPath . '\\';
  455. if (isset($this->prefixDirsPsr4[$search])) {
  456. $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
  457. foreach ($this->prefixDirsPsr4[$search] as $dir) {
  458. if (file_exists($file = $dir . $pathEnd)) {
  459. return $file;
  460. }
  461. }
  462. }
  463. }
  464. }
  465. // PSR-4 fallback dirs
  466. foreach ($this->fallbackDirsPsr4 as $dir) {
  467. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
  468. return $file;
  469. }
  470. }
  471. // PSR-0 lookup
  472. if (false !== $pos = strrpos($class, '\\')) {
  473. // namespaced class name
  474. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  475. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
  476. } else {
  477. // PEAR-like class name
  478. $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
  479. }
  480. if (isset($this->prefixesPsr0[$first])) {
  481. foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
  482. if (0 === strpos($class, $prefix)) {
  483. foreach ($dirs as $dir) {
  484. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  485. return $file;
  486. }
  487. }
  488. }
  489. }
  490. }
  491. // PSR-0 fallback dirs
  492. foreach ($this->fallbackDirsPsr0 as $dir) {
  493. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  494. return $file;
  495. }
  496. }
  497. // PSR-0 include paths.
  498. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
  499. return $file;
  500. }
  501. return false;
  502. }
  503. }
  504. /**
  505. * Scope isolated include.
  506. *
  507. * Prevents access to $this/self from included files.
  508. *
  509. * @param string $file
  510. * @return void
  511. * @private
  512. */
  513. function includeFile($file)
  514. {
  515. include $file;
  516. }