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.
 
 
 
 
 
 

580 wiersze
16 KiB

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