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 $prefixLengthsPsr4 = array();
47: private $prefixDirsPsr4 = array();
48: private $fallbackDirsPsr4 = array();
49:
50:
51: private $prefixesPsr0 = array();
52: private $fallbackDirsPsr0 = array();
53:
54: private $useIncludePath = false;
55: private $classMap = array();
56: private $classMapAuthoritative = false;
57: private $missingClasses = array();
58: private $apcuPrefix;
59:
60: public function getPrefixes()
61: {
62: if (!empty($this->prefixesPsr0)) {
63: return call_user_func_array('array_merge', $this->prefixesPsr0);
64: }
65:
66: return array();
67: }
68:
69: public function getPrefixesPsr4()
70: {
71: return $this->prefixDirsPsr4;
72: }
73:
74: public function getFallbackDirs()
75: {
76: return $this->fallbackDirsPsr0;
77: }
78:
79: public function getFallbackDirsPsr4()
80: {
81: return $this->fallbackDirsPsr4;
82: }
83:
84: public function getClassMap()
85: {
86: return $this->classMap;
87: }
88:
89: 90: 91:
92: public function addClassMap(array $classMap)
93: {
94: if ($this->classMap) {
95: $this->classMap = array_merge($this->classMap, $classMap);
96: } else {
97: $this->classMap = $classMap;
98: }
99: }
100:
101: 102: 103: 104: 105: 106: 107: 108:
109: public function add($prefix, $paths, $prepend = false)
110: {
111: if (!$prefix) {
112: if ($prepend) {
113: $this->fallbackDirsPsr0 = array_merge(
114: (array) $paths,
115: $this->fallbackDirsPsr0
116: );
117: } else {
118: $this->fallbackDirsPsr0 = array_merge(
119: $this->fallbackDirsPsr0,
120: (array) $paths
121: );
122: }
123:
124: return;
125: }
126:
127: $first = $prefix[0];
128: if (!isset($this->prefixesPsr0[$first][$prefix])) {
129: $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130:
131: return;
132: }
133: if ($prepend) {
134: $this->prefixesPsr0[$first][$prefix] = array_merge(
135: (array) $paths,
136: $this->prefixesPsr0[$first][$prefix]
137: );
138: } else {
139: $this->prefixesPsr0[$first][$prefix] = array_merge(
140: $this->prefixesPsr0[$first][$prefix],
141: (array) $paths
142: );
143: }
144: }
145:
146: 147: 148: 149: 150: 151: 152: 153: 154: 155:
156: public function addPsr4($prefix, $paths, $prepend = false)
157: {
158: if (!$prefix) {
159:
160: if ($prepend) {
161: $this->fallbackDirsPsr4 = array_merge(
162: (array) $paths,
163: $this->fallbackDirsPsr4
164: );
165: } else {
166: $this->fallbackDirsPsr4 = array_merge(
167: $this->fallbackDirsPsr4,
168: (array) $paths
169: );
170: }
171: } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172:
173: $length = strlen($prefix);
174: if ('\\' !== $prefix[$length - 1]) {
175: throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176: }
177: $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178: $this->prefixDirsPsr4[$prefix] = (array) $paths;
179: } elseif ($prepend) {
180:
181: $this->prefixDirsPsr4[$prefix] = array_merge(
182: (array) $paths,
183: $this->prefixDirsPsr4[$prefix]
184: );
185: } else {
186:
187: $this->prefixDirsPsr4[$prefix] = array_merge(
188: $this->prefixDirsPsr4[$prefix],
189: (array) $paths
190: );
191: }
192: }
193:
194: 195: 196: 197: 198: 199: 200:
201: public function set($prefix, $paths)
202: {
203: if (!$prefix) {
204: $this->fallbackDirsPsr0 = (array) $paths;
205: } else {
206: $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207: }
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217: 218:
219: public function setPsr4($prefix, $paths)
220: {
221: if (!$prefix) {
222: $this->fallbackDirsPsr4 = (array) $paths;
223: } else {
224: $length = strlen($prefix);
225: if ('\\' !== $prefix[$length - 1]) {
226: throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227: }
228: $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229: $this->prefixDirsPsr4[$prefix] = (array) $paths;
230: }
231: }
232:
233: 234: 235: 236: 237:
238: public function setUseIncludePath($useIncludePath)
239: {
240: $this->useIncludePath = $useIncludePath;
241: }
242:
243: 244: 245: 246: 247: 248:
249: public function getUseIncludePath()
250: {
251: return $this->useIncludePath;
252: }
253:
254: 255: 256: 257: 258: 259:
260: public function setClassMapAuthoritative($classMapAuthoritative)
261: {
262: $this->classMapAuthoritative = $classMapAuthoritative;
263: }
264:
265: 266: 267: 268: 269:
270: public function isClassMapAuthoritative()
271: {
272: return $this->classMapAuthoritative;
273: }
274:
275: 276: 277: 278: 279:
280: public function setApcuPrefix($apcuPrefix)
281: {
282: $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283: }
284:
285: 286: 287: 288: 289:
290: public function getApcuPrefix()
291: {
292: return $this->apcuPrefix;
293: }
294:
295: 296: 297: 298: 299:
300: public function register($prepend = false)
301: {
302: spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303: }
304:
305: 306: 307:
308: public function unregister()
309: {
310: spl_autoload_unregister(array($this, 'loadClass'));
311: }
312:
313: 314: 315: 316: 317: 318:
319: public function loadClass($class)
320: {
321: if ($file = $this->findFile($class)) {
322: includeFile($file);
323:
324: return true;
325: }
326: }
327:
328: 329: 330: 331: 332: 333: 334:
335: public function findFile($class)
336: {
337:
338: if (isset($this->classMap[$class])) {
339: return $this->classMap[$class];
340: }
341: if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342: return false;
343: }
344: if (null !== $this->apcuPrefix) {
345: $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346: if ($hit) {
347: return $file;
348: }
349: }
350:
351: $file = $this->findFileWithExtension($class, '.php');
352:
353:
354: if (false === $file && defined('HHVM_VERSION')) {
355: $file = $this->findFileWithExtension($class, '.hh');
356: }
357:
358: if (null !== $this->apcuPrefix) {
359: apcu_add($this->apcuPrefix.$class, $file);
360: }
361:
362: if (false === $file) {
363:
364: $this->missingClasses[$class] = true;
365: }
366:
367: return $file;
368: }
369:
370: private function findFileWithExtension($class, $ext)
371: {
372:
373: $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374:
375: $first = $class[0];
376: if (isset($this->prefixLengthsPsr4[$first])) {
377: $subPath = $class;
378: while (false !== $lastPos = strrpos($subPath, '\\')) {
379: $subPath = substr($subPath, 0, $lastPos);
380: $search = $subPath.'\\';
381: if (isset($this->prefixDirsPsr4[$search])) {
382: foreach ($this->prefixDirsPsr4[$search] as $dir) {
383: $length = $this->prefixLengthsPsr4[$first][$search];
384: if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
385: return $file;
386: }
387: }
388: }
389: }
390: }
391:
392:
393: foreach ($this->fallbackDirsPsr4 as $dir) {
394: if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395: return $file;
396: }
397: }
398:
399:
400: if (false !== $pos = strrpos($class, '\\')) {
401:
402: $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403: . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404: } else {
405:
406: $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407: }
408:
409: if (isset($this->prefixesPsr0[$first])) {
410: foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411: if (0 === strpos($class, $prefix)) {
412: foreach ($dirs as $dir) {
413: if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414: return $file;
415: }
416: }
417: }
418: }
419: }
420:
421:
422: foreach ($this->fallbackDirsPsr0 as $dir) {
423: if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424: return $file;
425: }
426: }
427:
428:
429: if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430: return $file;
431: }
432:
433: return false;
434: }
435: }
436:
437: 438: 439: 440: 441:
442: function includeFile($file)
443: {
444: include $file;
445: }
446: