vendor/doctrine-common/lib/Doctrine/Common/ClassLoader.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 /*
       
     3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
     4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
     5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
     6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
     7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
     8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
     9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    14  *
       
    15  * This software consists of voluntary contributions made by many individuals
       
    16  * and is licensed under the LGPL. For more information, see
       
    17  * <http://www.doctrine-project.org>.
       
    18  */
       
    19 
       
    20 namespace Doctrine\Common;
       
    21 
       
    22 /**
       
    23  * A <tt>ClassLoader</tt> is an autoloader for class files that can be
       
    24  * installed on the SPL autoload stack. It is a class loader that either loads only classes
       
    25  * of a specific namespace or all namespaces and it is suitable for working together
       
    26  * with other autoloaders in the SPL autoload stack.
       
    27  * 
       
    28  * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader
       
    29  * relies on the PHP <code>include_path</code>.
       
    30  * 
       
    31  * @author Roman Borschel <roman@code-factory.org>
       
    32  * @since 2.0
       
    33  */
       
    34 class ClassLoader
       
    35 {
       
    36     private $fileExtension = '.php';
       
    37     private $namespace;
       
    38     private $includePath;
       
    39     private $namespaceSeparator = '\\';
       
    40 
       
    41     /**
       
    42      * Creates a new <tt>ClassLoader</tt> that loads classes of the
       
    43      * specified namespace from the specified include path.
       
    44      *
       
    45      * If no include path is given, the ClassLoader relies on the PHP include_path.
       
    46      * If neither a namespace nor an include path is given, the ClassLoader will
       
    47      * be responsible for loading all classes, thereby relying on the PHP include_path.
       
    48      * 
       
    49      * @param string $ns The namespace of the classes to load.
       
    50      * @param string $includePath The base include path to use.
       
    51      */
       
    52     public function __construct($ns = null, $includePath = null)
       
    53     {
       
    54         $this->namespace = $ns;
       
    55         $this->includePath = $includePath;
       
    56     }
       
    57 
       
    58     /**
       
    59      * Sets the namespace separator used by classes in the namespace of this ClassLoader.
       
    60      * 
       
    61      * @param string $sep The separator to use.
       
    62      */
       
    63     public function setNamespaceSeparator($sep)
       
    64     {
       
    65         $this->namespaceSeparator = $sep;
       
    66     }
       
    67 
       
    68     /**
       
    69      * Gets the namespace separator used by classes in the namespace of this ClassLoader.
       
    70      * 
       
    71      * @return string
       
    72      */
       
    73     public function getNamespaceSeparator()
       
    74     {
       
    75         return $this->namespaceSeparator;
       
    76     }
       
    77 
       
    78     /**
       
    79      * Sets the base include path for all class files in the namespace of this ClassLoader.
       
    80      * 
       
    81      * @param string $includePath
       
    82      */
       
    83     public function setIncludePath($includePath)
       
    84     {
       
    85         $this->includePath = $includePath;
       
    86     }
       
    87 
       
    88     /**
       
    89      * Gets the base include path for all class files in the namespace of this ClassLoader.
       
    90      * 
       
    91      * @return string
       
    92      */
       
    93     public function getIncludePath()
       
    94     {
       
    95         return $this->includePath;
       
    96     }
       
    97 
       
    98     /**
       
    99      * Sets the file extension of class files in the namespace of this ClassLoader.
       
   100      * 
       
   101      * @param string $fileExtension
       
   102      */
       
   103     public function setFileExtension($fileExtension)
       
   104     {
       
   105         $this->fileExtension = $fileExtension;
       
   106     }
       
   107 
       
   108     /**
       
   109      * Gets the file extension of class files in the namespace of this ClassLoader.
       
   110      * 
       
   111      * @return string
       
   112      */
       
   113     public function getFileExtension()
       
   114     {
       
   115         return $this->fileExtension;
       
   116     }
       
   117 
       
   118     /**
       
   119      * Registers this ClassLoader on the SPL autoload stack.
       
   120      */
       
   121     public function register()
       
   122     {
       
   123         spl_autoload_register(array($this, 'loadClass'));
       
   124     }
       
   125 
       
   126     /**
       
   127      * Removes this ClassLoader from the SPL autoload stack.
       
   128      */
       
   129     public function unregister()
       
   130     {
       
   131         spl_autoload_unregister(array($this, 'loadClass'));
       
   132     }
       
   133 
       
   134     /**
       
   135      * Loads the given class or interface.
       
   136      *
       
   137      * @param string $classname The name of the class to load.
       
   138      * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
       
   139      */
       
   140     public function loadClass($className)
       
   141     {
       
   142         if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
       
   143             return false;
       
   144         }
       
   145 
       
   146         require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '')
       
   147                . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className)
       
   148                . $this->fileExtension;
       
   149         
       
   150         return true;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Asks this ClassLoader whether it can potentially load the class (file) with
       
   155      * the given name.
       
   156      *
       
   157      * @param string $className The fully-qualified name of the class.
       
   158      * @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise.
       
   159      */
       
   160     public function canLoadClass($className)
       
   161     {
       
   162         if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
       
   163             return false;
       
   164         }
       
   165 
       
   166         $file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension;
       
   167 
       
   168         if ($this->includePath !== null) {
       
   169             return file_exists($this->includePath . DIRECTORY_SEPARATOR . $file);
       
   170         }
       
   171 
       
   172         return self::fileExistsInIncludePath($file);
       
   173     }
       
   174 
       
   175     /**
       
   176      * Checks whether a class with a given name exists. A class "exists" if it is either
       
   177      * already defined in the current request or if there is an autoloader on the SPL
       
   178      * autoload stack that is a) responsible for the class in question and b) is able to
       
   179      * load a class file in which the class definition resides.
       
   180      *
       
   181      * If the class is not already defined, each autoloader in the SPL autoload stack
       
   182      * is asked whether it is able to tell if the class exists. If the autoloader is
       
   183      * a <tt>ClassLoader</tt>, {@link canLoadClass} is used, otherwise the autoload
       
   184      * function of the autoloader is invoked and expected to return a value that
       
   185      * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports
       
   186      * that the class exists, TRUE is returned.
       
   187      *
       
   188      * Note that, depending on what kinds of autoloaders are installed on the SPL
       
   189      * autoload stack, the class (file) might already be loaded as a result of checking
       
   190      * for its existence. This is not the case with a <tt>ClassLoader</tt>, who separates
       
   191      * these responsibilities.
       
   192      *
       
   193      * @param string $className The fully-qualified name of the class.
       
   194      * @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise.
       
   195      */
       
   196     public static function classExists($className)
       
   197     {
       
   198         if (class_exists($className, false)) {
       
   199             return true;
       
   200         }
       
   201 
       
   202         foreach (spl_autoload_functions() as $loader) {
       
   203             if (is_array($loader)) { // array(???, ???)
       
   204                 if (is_object($loader[0])) {
       
   205                     if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName')
       
   206                         if ($loader[0]->canLoadClass($className)) {
       
   207                             return true;
       
   208                         }
       
   209                     } else if ($loader[0]->{$loader[1]}($className)) {
       
   210                         return true;
       
   211                     }
       
   212                 } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
       
   213                     return true;
       
   214                 }
       
   215             } else if ($loader instanceof \Closure) { // function($className) {..}
       
   216                 if ($loader($className)) {
       
   217                     return true;
       
   218                 }
       
   219             } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
       
   220                 return true;
       
   221             }
       
   222         }
       
   223 
       
   224         return false;
       
   225     }
       
   226 
       
   227     /**
       
   228      * Gets the <tt>ClassLoader</tt> from the SPL autoload stack that is responsible
       
   229      * for (and is able to load) the class with the given name.
       
   230      *
       
   231      * @param string $className The name of the class.
       
   232      * @return The <tt>ClassLoader</tt> for the class or NULL if no such <tt>ClassLoader</tt> exists.
       
   233      */
       
   234     public static function getClassLoader($className)
       
   235     {
       
   236          foreach (spl_autoload_functions() as $loader) {
       
   237             if (is_array($loader)
       
   238                 && $loader[0] instanceof ClassLoader
       
   239                 && $loader[0]->canLoadClass($className)
       
   240             ) {
       
   241                 return $loader[0];
       
   242             }
       
   243         }
       
   244 
       
   245         return null;
       
   246     }
       
   247     
       
   248     /**
       
   249      * @param string $file The file relative path.
       
   250      * @return boolean Whether file exists in include_path.
       
   251      */
       
   252     public static function fileExistsInIncludePath($file)
       
   253     {
       
   254         foreach (explode(PATH_SEPARATOR, get_include_path()) as $dir) {
       
   255             if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
       
   256                 return true;
       
   257             }
       
   258         }
       
   259         return false;
       
   260     }
       
   261 }