1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22:
23:
24: require_once 'Zend/Loader.php';
25:
26: 27: 28: 29: 30: 31: 32: 33: 34:
35: class Zend_Loader_Autoloader
36: {
37: 38: 39:
40: protected static $_instance;
41:
42: 43: 44:
45: protected $_autoloaders = array();
46:
47: 48: 49:
50: protected $_defaultAutoloader = array('Zend_Loader', 'loadClass');
51:
52: 53: 54:
55: protected $_fallbackAutoloader = false;
56:
57: 58: 59:
60: protected $_internalAutoloader;
61:
62: 63: 64:
65: protected $_namespaces = array(
66: 'Zend_' => true,
67: 'ZendX_' => true,
68: );
69:
70: 71: 72:
73: protected $_namespaceAutoloaders = array();
74:
75: 76: 77:
78: protected $_suppressNotFoundWarnings = false;
79:
80: 81: 82:
83: protected $_zfPath;
84:
85: 86: 87: 88: 89:
90: public static function getInstance()
91: {
92: if (null === self::$_instance) {
93: self::$_instance = new self();
94: }
95: return self::$_instance;
96: }
97:
98: 99: 100: 101: 102:
103: public static function resetInstance()
104: {
105: self::$_instance = null;
106: }
107:
108: 109: 110: 111: 112: 113:
114: public static function autoload($class)
115: {
116: $self = self::getInstance();
117:
118: foreach ($self->getClassAutoloaders($class) as $autoloader) {
119: if ($autoloader instanceof Zend_Loader_Autoloader_Interface) {
120: if ($autoloader->autoload($class)) {
121: return true;
122: }
123: } elseif (is_array($autoloader)) {
124: if (call_user_func($autoloader, $class)) {
125: return true;
126: }
127: } elseif (is_string($autoloader) || is_callable($autoloader)) {
128: if ($autoloader($class)) {
129: return true;
130: }
131: }
132: }
133:
134: return false;
135: }
136:
137: 138: 139: 140: 141: 142:
143: public function setDefaultAutoloader($callback)
144: {
145: if (!is_callable($callback)) {
146: throw new Zend_Loader_Exception('Invalid callback specified for default autoloader');
147: }
148:
149: $this->_defaultAutoloader = $callback;
150: return $this;
151: }
152:
153: 154: 155: 156: 157:
158: public function getDefaultAutoloader()
159: {
160: return $this->_defaultAutoloader;
161: }
162:
163: 164: 165: 166: 167: 168:
169: public function setAutoloaders(array $autoloaders)
170: {
171: $this->_autoloaders = $autoloaders;
172: return $this;
173: }
174:
175: 176: 177: 178: 179:
180: public function getAutoloaders()
181: {
182: return $this->_autoloaders;
183: }
184:
185: 186: 187: 188: 189: 190:
191: public function getNamespaceAutoloaders($namespace)
192: {
193: $namespace = (string) $namespace;
194: if (!array_key_exists($namespace, $this->_namespaceAutoloaders)) {
195: return array();
196: }
197: return $this->_namespaceAutoloaders[$namespace];
198: }
199:
200: 201: 202: 203: 204: 205:
206: public function registerNamespace($namespace)
207: {
208: if (is_string($namespace)) {
209: $namespace = (array) $namespace;
210: } elseif (!is_array($namespace)) {
211: throw new Zend_Loader_Exception('Invalid namespace provided');
212: }
213:
214: foreach ($namespace as $ns) {
215: if (!isset($this->_namespaces[$ns])) {
216: $this->_namespaces[$ns] = true;
217: }
218: }
219: return $this;
220: }
221:
222: 223: 224: 225: 226: 227:
228: public function unregisterNamespace($namespace)
229: {
230: if (is_string($namespace)) {
231: $namespace = (array) $namespace;
232: } elseif (!is_array($namespace)) {
233: throw new Zend_Loader_Exception('Invalid namespace provided');
234: }
235:
236: foreach ($namespace as $ns) {
237: if (isset($this->_namespaces[$ns])) {
238: unset($this->_namespaces[$ns]);
239: }
240: }
241: return $this;
242: }
243:
244: 245: 246: 247: 248:
249: public function getRegisteredNamespaces()
250: {
251: return array_keys($this->_namespaces);
252: }
253:
254: public function setZfPath($spec, $version = 'latest')
255: {
256: $path = $spec;
257: if (is_array($spec)) {
258: if (!isset($spec['path'])) {
259: throw new Zend_Loader_Exception('No path specified for ZF');
260: }
261: $path = $spec['path'];
262: if (isset($spec['version'])) {
263: $version = $spec['version'];
264: }
265: }
266:
267: $this->_zfPath = $this->_getVersionPath($path, $version);
268: set_include_path(implode(PATH_SEPARATOR, array(
269: $this->_zfPath,
270: get_include_path(),
271: )));
272: return $this;
273: }
274:
275: public function getZfPath()
276: {
277: return $this->_zfPath;
278: }
279:
280: 281: 282: 283: 284: 285:
286: public function suppressNotFoundWarnings($flag = null)
287: {
288: if (null === $flag) {
289: return $this->_suppressNotFoundWarnings;
290: }
291: $this->_suppressNotFoundWarnings = (bool) $flag;
292: return $this;
293: }
294:
295: 296: 297: 298: 299: 300:
301: public function setFallbackAutoloader($flag)
302: {
303: $this->_fallbackAutoloader = (bool) $flag;
304: return $this;
305: }
306:
307: 308: 309: 310: 311:
312: public function isFallbackAutoloader()
313: {
314: return $this->_fallbackAutoloader;
315: }
316:
317: 318: 319: 320: 321: 322: 323: 324: 325: 326:
327: public function getClassAutoloaders($class)
328: {
329: $namespace = false;
330: $autoloaders = array();
331:
332:
333: foreach (array_keys($this->_namespaceAutoloaders) as $ns) {
334: if ('' == $ns) {
335: continue;
336: }
337: if (0 === strpos($class, $ns)) {
338: $namespace = $ns;
339: $autoloaders = $autoloaders + $this->getNamespaceAutoloaders($ns);
340: break;
341: }
342: }
343:
344:
345: foreach ($this->getRegisteredNamespaces() as $ns) {
346: if (0 === strpos($class, $ns)) {
347: $namespace = $ns;
348: $autoloaders[] = $this->_internalAutoloader;
349: break;
350: }
351: }
352:
353:
354: $autoloaders = $autoloaders + $this->getNamespaceAutoloaders('');
355:
356:
357: if (!$namespace && $this->isFallbackAutoloader()) {
358: $autoloaders[] = $this->_internalAutoloader;
359: }
360:
361: return $autoloaders;
362: }
363:
364: 365: 366: 367: 368: 369: 370:
371: public function unshiftAutoloader($callback, $namespace = '')
372: {
373: $autoloaders = $this->getAutoloaders();
374: array_unshift($autoloaders, $callback);
375: $this->setAutoloaders($autoloaders);
376:
377: $namespace = (array) $namespace;
378: foreach ($namespace as $ns) {
379: $autoloaders = $this->getNamespaceAutoloaders($ns);
380: array_unshift($autoloaders, $callback);
381: $this->_setNamespaceAutoloaders($autoloaders, $ns);
382: }
383:
384: return $this;
385: }
386:
387: 388: 389: 390: 391: 392: 393:
394: public function pushAutoloader($callback, $namespace = '')
395: {
396: $autoloaders = $this->getAutoloaders();
397: array_push($autoloaders, $callback);
398: $this->setAutoloaders($autoloaders);
399:
400: $namespace = (array) $namespace;
401: foreach ($namespace as $ns) {
402: $autoloaders = $this->getNamespaceAutoloaders($ns);
403: array_push($autoloaders, $callback);
404: $this->_setNamespaceAutoloaders($autoloaders, $ns);
405: }
406:
407: return $this;
408: }
409:
410: 411: 412: 413: 414: 415: 416:
417: public function removeAutoloader($callback, $namespace = null)
418: {
419: if (null === $namespace) {
420: $autoloaders = $this->getAutoloaders();
421: if (false !== ($index = array_search($callback, $autoloaders, true))) {
422: unset($autoloaders[$index]);
423: $this->setAutoloaders($autoloaders);
424: }
425:
426: foreach ($this->_namespaceAutoloaders as $ns => $autoloaders) {
427: if (false !== ($index = array_search($callback, $autoloaders, true))) {
428: unset($autoloaders[$index]);
429: $this->_setNamespaceAutoloaders($autoloaders, $ns);
430: }
431: }
432: } else {
433: $namespace = (array) $namespace;
434: foreach ($namespace as $ns) {
435: $autoloaders = $this->getNamespaceAutoloaders($ns);
436: if (false !== ($index = array_search($callback, $autoloaders, true))) {
437: unset($autoloaders[$index]);
438: $this->_setNamespaceAutoloaders($autoloaders, $ns);
439: }
440: }
441: }
442:
443: return $this;
444: }
445:
446: 447: 448: 449: 450: 451: 452:
453: protected function __construct()
454: {
455: spl_autoload_register(array(__CLASS__, 'autoload'));
456: $this->_internalAutoloader = array($this, '_autoload');
457: }
458:
459: 460: 461: 462: 463: 464:
465: protected function _autoload($class)
466: {
467: $callback = $this->getDefaultAutoloader();
468: try {
469: if ($this->suppressNotFoundWarnings()) {
470: @call_user_func($callback, $class);
471: } else {
472: call_user_func($callback, $class);
473: }
474: return $class;
475: } catch (Zend_Exception $e) {
476: return false;
477: }
478: }
479:
480: 481: 482: 483: 484: 485: 486:
487: protected function _setNamespaceAutoloaders(array $autoloaders, $namespace = '')
488: {
489: $namespace = (string) $namespace;
490: $this->_namespaceAutoloaders[$namespace] = $autoloaders;
491: return $this;
492: }
493:
494: 495: 496: 497: 498: 499: 500:
501: protected function _getVersionPath($path, $version)
502: {
503: $type = $this->_getVersionType($version);
504:
505: if ($type == 'latest') {
506: $version = 'latest';
507: }
508:
509: $availableVersions = $this->_getAvailableVersions($path, $version);
510: if (empty($availableVersions)) {
511: throw new Zend_Loader_Exception('No valid ZF installations discovered');
512: }
513:
514: $matchedVersion = array_pop($availableVersions);
515: return $matchedVersion;
516: }
517:
518: 519: 520: 521: 522: 523: 524:
525: protected function _getVersionType($version)
526: {
527: if (strtolower($version) == 'latest') {
528: return 'latest';
529: }
530:
531: $parts = explode('.', $version);
532: $count = count($parts);
533: if (1 == $count) {
534: return 'major';
535: }
536: if (2 == $count) {
537: return 'minor';
538: }
539: if (3 < $count) {
540: throw new Zend_Loader_Exception('Invalid version string provided');
541: }
542: return 'specific';
543: }
544:
545: 546: 547: 548: 549: 550: 551:
552: protected function _getAvailableVersions($path, $version)
553: {
554: if (!is_dir($path)) {
555: throw new Zend_Loader_Exception('Invalid ZF path provided');
556: }
557:
558: $path = rtrim($path, '/');
559: $path = rtrim($path, '\\');
560: $versionLen = strlen($version);
561: $versions = array();
562: $dirs = glob("$path/*", GLOB_ONLYDIR);
563: foreach ((array) $dirs as $dir) {
564: $dirName = substr($dir, strlen($path) + 1);
565: if (!preg_match('/^(?:ZendFramework-)?(\d+\.\d+\.\d+((a|b|pl|pr|p|rc)\d+)?)(?:-minimal)?$/i', $dirName, $matches)) {
566: continue;
567: }
568:
569: $matchedVersion = $matches[1];
570:
571: if (('latest' == $version)
572: || ((strlen($matchedVersion) >= $versionLen)
573: && (0 === strpos($matchedVersion, $version)))
574: ) {
575: $versions[$matchedVersion] = $dir . '/library';
576: }
577: }
578:
579: uksort($versions, 'version_compare');
580: return $versions;
581: }
582: }
583: