Plugin to allow visitor contributions to WordPress posts, wiki style.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

414 Zeilen
12KB

  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 = array();
  44. private $prefixDirsPsr4 = array();
  45. private $fallbackDirsPsr4 = array();
  46. // PSR-0
  47. private $prefixesPsr0 = array();
  48. private $fallbackDirsPsr0 = array();
  49. private $useIncludePath = false;
  50. private $classMap = array();
  51. private $classMapAuthoritative = false;
  52. public function getPrefixes()
  53. {
  54. if (!empty($this->prefixesPsr0)) {
  55. return call_user_func_array('array_merge', $this->prefixesPsr0);
  56. }
  57. return array();
  58. }
  59. public function getPrefixesPsr4()
  60. {
  61. return $this->prefixDirsPsr4;
  62. }
  63. public function getFallbackDirs()
  64. {
  65. return $this->fallbackDirsPsr0;
  66. }
  67. public function getFallbackDirsPsr4()
  68. {
  69. return $this->fallbackDirsPsr4;
  70. }
  71. public function getClassMap()
  72. {
  73. return $this->classMap;
  74. }
  75. /**
  76. * @param array $classMap Class to filename map
  77. */
  78. public function addClassMap(array $classMap)
  79. {
  80. if ($this->classMap) {
  81. $this->classMap = array_merge($this->classMap, $classMap);
  82. } else {
  83. $this->classMap = $classMap;
  84. }
  85. }
  86. /**
  87. * Registers a set of PSR-0 directories for a given prefix, either
  88. * appending or prepending to the ones previously set for this prefix.
  89. *
  90. * @param string $prefix The prefix
  91. * @param array|string $paths The PSR-0 root directories
  92. * @param bool $prepend Whether to prepend the directories
  93. */
  94. public function add($prefix, $paths, $prepend = false)
  95. {
  96. if (!$prefix) {
  97. if ($prepend) {
  98. $this->fallbackDirsPsr0 = array_merge(
  99. (array) $paths,
  100. $this->fallbackDirsPsr0
  101. );
  102. } else {
  103. $this->fallbackDirsPsr0 = array_merge(
  104. $this->fallbackDirsPsr0,
  105. (array) $paths
  106. );
  107. }
  108. return;
  109. }
  110. $first = $prefix[0];
  111. if (!isset($this->prefixesPsr0[$first][$prefix])) {
  112. $this->prefixesPsr0[$first][$prefix] = (array) $paths;
  113. return;
  114. }
  115. if ($prepend) {
  116. $this->prefixesPsr0[$first][$prefix] = array_merge(
  117. (array) $paths,
  118. $this->prefixesPsr0[$first][$prefix]
  119. );
  120. } else {
  121. $this->prefixesPsr0[$first][$prefix] = array_merge(
  122. $this->prefixesPsr0[$first][$prefix],
  123. (array) $paths
  124. );
  125. }
  126. }
  127. /**
  128. * Registers a set of PSR-4 directories for a given namespace, either
  129. * appending or prepending to the ones previously set for this namespace.
  130. *
  131. * @param string $prefix The prefix/namespace, with trailing '\\'
  132. * @param array|string $paths The PSR-4 base directories
  133. * @param bool $prepend Whether to prepend the directories
  134. *
  135. * @throws \InvalidArgumentException
  136. */
  137. public function addPsr4($prefix, $paths, $prepend = false)
  138. {
  139. if (!$prefix) {
  140. // Register directories for the root namespace.
  141. if ($prepend) {
  142. $this->fallbackDirsPsr4 = array_merge(
  143. (array) $paths,
  144. $this->fallbackDirsPsr4
  145. );
  146. } else {
  147. $this->fallbackDirsPsr4 = array_merge(
  148. $this->fallbackDirsPsr4,
  149. (array) $paths
  150. );
  151. }
  152. } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
  153. // Register directories for a new namespace.
  154. $length = strlen($prefix);
  155. if ('\\' !== $prefix[$length - 1]) {
  156. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  157. }
  158. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  159. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  160. } elseif ($prepend) {
  161. // Prepend directories for an already registered namespace.
  162. $this->prefixDirsPsr4[$prefix] = array_merge(
  163. (array) $paths,
  164. $this->prefixDirsPsr4[$prefix]
  165. );
  166. } else {
  167. // Append directories for an already registered namespace.
  168. $this->prefixDirsPsr4[$prefix] = array_merge(
  169. $this->prefixDirsPsr4[$prefix],
  170. (array) $paths
  171. );
  172. }
  173. }
  174. /**
  175. * Registers a set of PSR-0 directories for a given prefix,
  176. * replacing any others previously set for this prefix.
  177. *
  178. * @param string $prefix The prefix
  179. * @param array|string $paths The PSR-0 base directories
  180. */
  181. public function set($prefix, $paths)
  182. {
  183. if (!$prefix) {
  184. $this->fallbackDirsPsr0 = (array) $paths;
  185. } else {
  186. $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
  187. }
  188. }
  189. /**
  190. * Registers a set of PSR-4 directories for a given namespace,
  191. * replacing any others previously set for this namespace.
  192. *
  193. * @param string $prefix The prefix/namespace, with trailing '\\'
  194. * @param array|string $paths The PSR-4 base directories
  195. *
  196. * @throws \InvalidArgumentException
  197. */
  198. public function setPsr4($prefix, $paths)
  199. {
  200. if (!$prefix) {
  201. $this->fallbackDirsPsr4 = (array) $paths;
  202. } else {
  203. $length = strlen($prefix);
  204. if ('\\' !== $prefix[$length - 1]) {
  205. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  206. }
  207. $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  208. $this->prefixDirsPsr4[$prefix] = (array) $paths;
  209. }
  210. }
  211. /**
  212. * Turns on searching the include path for class files.
  213. *
  214. * @param bool $useIncludePath
  215. */
  216. public function setUseIncludePath($useIncludePath)
  217. {
  218. $this->useIncludePath = $useIncludePath;
  219. }
  220. /**
  221. * Can be used to check if the autoloader uses the include path to check
  222. * for classes.
  223. *
  224. * @return bool
  225. */
  226. public function getUseIncludePath()
  227. {
  228. return $this->useIncludePath;
  229. }
  230. /**
  231. * Turns off searching the prefix and fallback directories for classes
  232. * that have not been registered with the class map.
  233. *
  234. * @param bool $classMapAuthoritative
  235. */
  236. public function setClassMapAuthoritative($classMapAuthoritative)
  237. {
  238. $this->classMapAuthoritative = $classMapAuthoritative;
  239. }
  240. /**
  241. * Should class lookup fail if not found in the current class map?
  242. *
  243. * @return bool
  244. */
  245. public function isClassMapAuthoritative()
  246. {
  247. return $this->classMapAuthoritative;
  248. }
  249. /**
  250. * Registers this instance as an autoloader.
  251. *
  252. * @param bool $prepend Whether to prepend the autoloader or not
  253. */
  254. public function register($prepend = false)
  255. {
  256. spl_autoload_register(array($this, 'loadClass'), true, $prepend);
  257. }
  258. /**
  259. * Unregisters this instance as an autoloader.
  260. */
  261. public function unregister()
  262. {
  263. spl_autoload_unregister(array($this, 'loadClass'));
  264. }
  265. /**
  266. * Loads the given class or interface.
  267. *
  268. * @param string $class The name of the class
  269. * @return bool|null True if loaded, null otherwise
  270. */
  271. public function loadClass($class)
  272. {
  273. if ($file = $this->findFile($class)) {
  274. includeFile($file);
  275. return true;
  276. }
  277. }
  278. /**
  279. * Finds the path to the file where the class is defined.
  280. *
  281. * @param string $class The name of the class
  282. *
  283. * @return string|false The path if found, false otherwise
  284. */
  285. public function findFile($class)
  286. {
  287. // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
  288. if ('\\' == $class[0]) {
  289. $class = substr($class, 1);
  290. }
  291. // class map lookup
  292. if (isset($this->classMap[$class])) {
  293. return $this->classMap[$class];
  294. }
  295. if ($this->classMapAuthoritative) {
  296. return false;
  297. }
  298. $file = $this->findFileWithExtension($class, '.php');
  299. // Search for Hack files if we are running on HHVM
  300. if ($file === null && defined('HHVM_VERSION')) {
  301. $file = $this->findFileWithExtension($class, '.hh');
  302. }
  303. if ($file === null) {
  304. // Remember that this class does not exist.
  305. return $this->classMap[$class] = false;
  306. }
  307. return $file;
  308. }
  309. private function findFileWithExtension($class, $ext)
  310. {
  311. // PSR-4 lookup
  312. $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
  313. $first = $class[0];
  314. if (isset($this->prefixLengthsPsr4[$first])) {
  315. foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
  316. if (0 === strpos($class, $prefix)) {
  317. foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
  318. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
  319. return $file;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. // PSR-4 fallback dirs
  326. foreach ($this->fallbackDirsPsr4 as $dir) {
  327. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
  328. return $file;
  329. }
  330. }
  331. // PSR-0 lookup
  332. if (false !== $pos = strrpos($class, '\\')) {
  333. // namespaced class name
  334. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  335. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
  336. } else {
  337. // PEAR-like class name
  338. $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
  339. }
  340. if (isset($this->prefixesPsr0[$first])) {
  341. foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
  342. if (0 === strpos($class, $prefix)) {
  343. foreach ($dirs as $dir) {
  344. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  345. return $file;
  346. }
  347. }
  348. }
  349. }
  350. }
  351. // PSR-0 fallback dirs
  352. foreach ($this->fallbackDirsPsr0 as $dir) {
  353. if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
  354. return $file;
  355. }
  356. }
  357. // PSR-0 include paths.
  358. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
  359. return $file;
  360. }
  361. }
  362. }
  363. /**
  364. * Scope isolated include.
  365. *
  366. * Prevents access to $this/self from included files.
  367. */
  368. function includeFile($file)
  369. {
  370. include $file;
  371. }