source: trunk/library/Zend/Loader/Autoloader.php @ 5146

Revision 5146, 16.2 KB checked in by wmerlotto, 12 years ago (diff)

Ticket #2305 - Enviando alteracoes, desenvolvidas internamente na Prognus. Library: adicionando arquivos.

Line 
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category   Zend
16 * @package    Zend_Loader
17 * @subpackage Autoloader
18 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
19 * @version    $Id: Autoloader.php 23161 2010-10-19 16:08:36Z matthew $
20 * @license    http://framework.zend.com/license/new-bsd     New BSD License
21 */
22
23/** Zend_Loader */
24require_once 'Zend/Loader.php';
25
26/**
27 * Autoloader stack and namespace autoloader
28 *
29 * @uses       Zend_Loader_Autoloader
30 * @package    Zend_Loader
31 * @subpackage Autoloader
32 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
33 * @license    http://framework.zend.com/license/new-bsd     New BSD License
34 */
35class Zend_Loader_Autoloader
36{
37    /**
38     * @var Zend_Loader_Autoloader Singleton instance
39     */
40    protected static $_instance;
41
42    /**
43     * @var array Concrete autoloader callback implementations
44     */
45    protected $_autoloaders = array();
46
47    /**
48     * @var array Default autoloader callback
49     */
50    protected $_defaultAutoloader = array('Zend_Loader', 'loadClass');
51
52    /**
53     * @var bool Whether or not to act as a fallback autoloader
54     */
55    protected $_fallbackAutoloader = false;
56
57    /**
58     * @var array Callback for internal autoloader implementation
59     */
60    protected $_internalAutoloader;
61
62    /**
63     * @var array Supported namespaces 'Zend' and 'ZendX' by default.
64     */
65    protected $_namespaces = array(
66        'Zend_'  => true,
67        'ZendX_' => true,
68    );
69
70    /**
71     * @var array Namespace-specific autoloaders
72     */
73    protected $_namespaceAutoloaders = array();
74
75    /**
76     * @var bool Whether or not to suppress file not found warnings
77     */
78    protected $_suppressNotFoundWarnings = false;
79
80    /**
81     * @var null|string
82     */
83    protected $_zfPath;
84
85    /**
86     * Retrieve singleton instance
87     *
88     * @return Zend_Loader_Autoloader
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     * Reset the singleton instance
100     *
101     * @return void
102     */
103    public static function resetInstance()
104    {
105        self::$_instance = null;
106    }
107
108    /**
109     * Autoload a class
110     *
111     * @param  string $class
112     * @return bool
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     * Set the default autoloader implementation
139     *
140     * @param  string|array $callback PHP callback
141     * @return void
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     * Retrieve the default autoloader callback
155     *
156     * @return string|array PHP Callback
157     */
158    public function getDefaultAutoloader()
159    {
160        return $this->_defaultAutoloader;
161    }
162
163    /**
164     * Set several autoloader callbacks at once
165     *
166     * @param  array $autoloaders Array of PHP callbacks (or Zend_Loader_Autoloader_Interface implementations) to act as autoloaders
167     * @return Zend_Loader_Autoloader
168     */
169    public function setAutoloaders(array $autoloaders)
170    {
171        $this->_autoloaders = $autoloaders;
172        return $this;
173    }
174
175    /**
176     * Get attached autoloader implementations
177     *
178     * @return array
179     */
180    public function getAutoloaders()
181    {
182        return $this->_autoloaders;
183    }
184
185    /**
186     * Return all autoloaders for a given namespace
187     *
188     * @param  string $namespace
189     * @return array
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     * Register a namespace to autoload
202     *
203     * @param  string|array $namespace
204     * @return Zend_Loader_Autoloader
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     * Unload a registered autoload namespace
224     *
225     * @param  string|array $namespace
226     * @return Zend_Loader_Autoloader
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     * Get a list of registered autoload namespaces
246     *
247     * @return array
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     * Get or set the value of the "suppress not found warnings" flag
282     *
283     * @param  null|bool $flag
284     * @return bool|Zend_Loader_Autoloader Returns boolean if no argument is passed, object instance otherwise
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     * Indicate whether or not this autoloader should be a fallback autoloader
297     *
298     * @param  bool $flag
299     * @return Zend_Loader_Autoloader
300     */
301    public function setFallbackAutoloader($flag)
302    {
303        $this->_fallbackAutoloader = (bool) $flag;
304        return $this;
305    }
306
307    /**
308     * Is this instance acting as a fallback autoloader?
309     *
310     * @return bool
311     */
312    public function isFallbackAutoloader()
313    {
314        return $this->_fallbackAutoloader;
315    }
316
317    /**
318     * Get autoloaders to use when matching class
319     *
320     * Determines if the class matches a registered namespace, and, if so,
321     * returns only the autoloaders for that namespace. Otherwise, it returns
322     * all non-namespaced autoloaders.
323     *
324     * @param  string $class
325     * @return array Array of autoloaders to use
326     */
327    public function getClassAutoloaders($class)
328    {
329        $namespace   = false;
330        $autoloaders = array();
331
332        // Add concrete namespaced autoloaders
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        // Add internal namespaced autoloader
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        // Add non-namespaced autoloaders
354        $autoloaders = $autoloaders + $this->getNamespaceAutoloaders('');
355
356        // Add fallback autoloader
357        if (!$namespace && $this->isFallbackAutoloader()) {
358            $autoloaders[] = $this->_internalAutoloader;
359        }
360
361        return $autoloaders;
362    }
363
364    /**
365     * Add an autoloader to the beginning of the stack
366     *
367     * @param  object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
368     * @param  string|array $namespace Specific namespace(s) under which to register callback
369     * @return Zend_Loader_Autoloader
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     * Append an autoloader to the autoloader stack
389     *
390     * @param  object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
391     * @param  string|array $namespace Specific namespace(s) under which to register callback
392     * @return Zend_Loader_Autoloader
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     * Remove an autoloader from the autoloader stack
412     *
413     * @param  object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation
414     * @param  null|string|array $namespace Specific namespace(s) from which to remove autoloader
415     * @return Zend_Loader_Autoloader
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     * Constructor
448     *
449     * Registers instance with spl_autoload stack
450     *
451     * @return void
452     */
453    protected function __construct()
454    {
455        spl_autoload_register(array(__CLASS__, 'autoload'));
456        $this->_internalAutoloader = array($this, '_autoload');
457    }
458
459    /**
460     * Internal autoloader implementation
461     *
462     * @param  string $class
463     * @return bool
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     * Set autoloaders for a specific namespace
482     *
483     * @param  array $autoloaders
484     * @param  string $namespace
485     * @return Zend_Loader_Autoloader
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     * Retrieve the filesystem path for the requested ZF version
496     *
497     * @param  string $path
498     * @param  string $version
499     * @return void
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     * Retrieve the ZF version type
520     *
521     * @param  string $version
522     * @return string "latest", "major", "minor", or "specific"
523     * @throws Zend_Loader_Exception if version string contains too many dots
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     * Get available versions for the version type requested
547     *
548     * @param  string $path
549     * @param  string $version
550     * @return array
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}
Note: See TracBrowser for help on using the repository browser.