xref: /plugin/pureldap/vendor/composer/ClassLoader.php (revision fd0855eca89b78737f4256f2dab98af86002431b)
10b3fd2d3SAndreas Gohr<?php
20b3fd2d3SAndreas Gohr
30b3fd2d3SAndreas Gohr/*
40b3fd2d3SAndreas Gohr * This file is part of Composer.
50b3fd2d3SAndreas Gohr *
60b3fd2d3SAndreas Gohr * (c) Nils Adermann <naderman@naderman.de>
70b3fd2d3SAndreas Gohr *     Jordi Boggiano <j.boggiano@seld.be>
80b3fd2d3SAndreas Gohr *
90b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE
100b3fd2d3SAndreas Gohr * file that was distributed with this source code.
110b3fd2d3SAndreas Gohr */
120b3fd2d3SAndreas Gohr
130b3fd2d3SAndreas Gohrnamespace Composer\Autoload;
140b3fd2d3SAndreas Gohr
150b3fd2d3SAndreas Gohr/**
160b3fd2d3SAndreas Gohr * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
170b3fd2d3SAndreas Gohr *
180b3fd2d3SAndreas Gohr *     $loader = new \Composer\Autoload\ClassLoader();
190b3fd2d3SAndreas Gohr *
200b3fd2d3SAndreas Gohr *     // register classes with namespaces
210b3fd2d3SAndreas Gohr *     $loader->add('Symfony\Component', __DIR__.'/component');
220b3fd2d3SAndreas Gohr *     $loader->add('Symfony',           __DIR__.'/framework');
230b3fd2d3SAndreas Gohr *
240b3fd2d3SAndreas Gohr *     // activate the autoloader
250b3fd2d3SAndreas Gohr *     $loader->register();
260b3fd2d3SAndreas Gohr *
270b3fd2d3SAndreas Gohr *     // to enable searching the include path (eg. for PEAR packages)
280b3fd2d3SAndreas Gohr *     $loader->setUseIncludePath(true);
290b3fd2d3SAndreas Gohr *
300b3fd2d3SAndreas Gohr * In this example, if you try to use a class in the Symfony\Component
310b3fd2d3SAndreas Gohr * namespace or one of its children (Symfony\Component\Console for instance),
320b3fd2d3SAndreas Gohr * the autoloader will first look for the class under the component/
330b3fd2d3SAndreas Gohr * directory, and it will then fallback to the framework/ directory if not
340b3fd2d3SAndreas Gohr * found before giving up.
350b3fd2d3SAndreas Gohr *
360b3fd2d3SAndreas Gohr * This class is loosely based on the Symfony UniversalClassLoader.
370b3fd2d3SAndreas Gohr *
380b3fd2d3SAndreas Gohr * @author Fabien Potencier <fabien@symfony.com>
390b3fd2d3SAndreas Gohr * @author Jordi Boggiano <j.boggiano@seld.be>
40*fd0855ecSAndreas Gohr * @see    https://www.php-fig.org/psr/psr-0/
41*fd0855ecSAndreas Gohr * @see    https://www.php-fig.org/psr/psr-4/
420b3fd2d3SAndreas Gohr */
430b3fd2d3SAndreas Gohrclass ClassLoader
440b3fd2d3SAndreas Gohr{
45*fd0855ecSAndreas Gohr    private $vendorDir;
46*fd0855ecSAndreas Gohr
470b3fd2d3SAndreas Gohr    // PSR-4
480b3fd2d3SAndreas Gohr    private $prefixLengthsPsr4 = array();
490b3fd2d3SAndreas Gohr    private $prefixDirsPsr4 = array();
500b3fd2d3SAndreas Gohr    private $fallbackDirsPsr4 = array();
510b3fd2d3SAndreas Gohr
520b3fd2d3SAndreas Gohr    // PSR-0
530b3fd2d3SAndreas Gohr    private $prefixesPsr0 = array();
540b3fd2d3SAndreas Gohr    private $fallbackDirsPsr0 = array();
550b3fd2d3SAndreas Gohr
560b3fd2d3SAndreas Gohr    private $useIncludePath = false;
570b3fd2d3SAndreas Gohr    private $classMap = array();
580b3fd2d3SAndreas Gohr    private $classMapAuthoritative = false;
590b3fd2d3SAndreas Gohr    private $missingClasses = array();
600b3fd2d3SAndreas Gohr    private $apcuPrefix;
610b3fd2d3SAndreas Gohr
62*fd0855ecSAndreas Gohr    private static $registeredLoaders = array();
63*fd0855ecSAndreas Gohr
64*fd0855ecSAndreas Gohr    public function __construct($vendorDir = null)
65*fd0855ecSAndreas Gohr    {
66*fd0855ecSAndreas Gohr        $this->vendorDir = $vendorDir;
67*fd0855ecSAndreas Gohr    }
68*fd0855ecSAndreas Gohr
690b3fd2d3SAndreas Gohr    public function getPrefixes()
700b3fd2d3SAndreas Gohr    {
710b3fd2d3SAndreas Gohr        if (!empty($this->prefixesPsr0)) {
72*fd0855ecSAndreas Gohr            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
730b3fd2d3SAndreas Gohr        }
740b3fd2d3SAndreas Gohr
750b3fd2d3SAndreas Gohr        return array();
760b3fd2d3SAndreas Gohr    }
770b3fd2d3SAndreas Gohr
780b3fd2d3SAndreas Gohr    public function getPrefixesPsr4()
790b3fd2d3SAndreas Gohr    {
800b3fd2d3SAndreas Gohr        return $this->prefixDirsPsr4;
810b3fd2d3SAndreas Gohr    }
820b3fd2d3SAndreas Gohr
830b3fd2d3SAndreas Gohr    public function getFallbackDirs()
840b3fd2d3SAndreas Gohr    {
850b3fd2d3SAndreas Gohr        return $this->fallbackDirsPsr0;
860b3fd2d3SAndreas Gohr    }
870b3fd2d3SAndreas Gohr
880b3fd2d3SAndreas Gohr    public function getFallbackDirsPsr4()
890b3fd2d3SAndreas Gohr    {
900b3fd2d3SAndreas Gohr        return $this->fallbackDirsPsr4;
910b3fd2d3SAndreas Gohr    }
920b3fd2d3SAndreas Gohr
930b3fd2d3SAndreas Gohr    public function getClassMap()
940b3fd2d3SAndreas Gohr    {
950b3fd2d3SAndreas Gohr        return $this->classMap;
960b3fd2d3SAndreas Gohr    }
970b3fd2d3SAndreas Gohr
980b3fd2d3SAndreas Gohr    /**
990b3fd2d3SAndreas Gohr     * @param array $classMap Class to filename map
1000b3fd2d3SAndreas Gohr     */
1010b3fd2d3SAndreas Gohr    public function addClassMap(array $classMap)
1020b3fd2d3SAndreas Gohr    {
1030b3fd2d3SAndreas Gohr        if ($this->classMap) {
1040b3fd2d3SAndreas Gohr            $this->classMap = array_merge($this->classMap, $classMap);
1050b3fd2d3SAndreas Gohr        } else {
1060b3fd2d3SAndreas Gohr            $this->classMap = $classMap;
1070b3fd2d3SAndreas Gohr        }
1080b3fd2d3SAndreas Gohr    }
1090b3fd2d3SAndreas Gohr
1100b3fd2d3SAndreas Gohr    /**
1110b3fd2d3SAndreas Gohr     * Registers a set of PSR-0 directories for a given prefix, either
1120b3fd2d3SAndreas Gohr     * appending or prepending to the ones previously set for this prefix.
1130b3fd2d3SAndreas Gohr     *
1140b3fd2d3SAndreas Gohr     * @param string       $prefix  The prefix
1150b3fd2d3SAndreas Gohr     * @param array|string $paths   The PSR-0 root directories
1160b3fd2d3SAndreas Gohr     * @param bool         $prepend Whether to prepend the directories
1170b3fd2d3SAndreas Gohr     */
1180b3fd2d3SAndreas Gohr    public function add($prefix, $paths, $prepend = false)
1190b3fd2d3SAndreas Gohr    {
1200b3fd2d3SAndreas Gohr        if (!$prefix) {
1210b3fd2d3SAndreas Gohr            if ($prepend) {
1220b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr0 = array_merge(
1230b3fd2d3SAndreas Gohr                    (array) $paths,
1240b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr0
1250b3fd2d3SAndreas Gohr                );
1260b3fd2d3SAndreas Gohr            } else {
1270b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr0 = array_merge(
1280b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr0,
1290b3fd2d3SAndreas Gohr                    (array) $paths
1300b3fd2d3SAndreas Gohr                );
1310b3fd2d3SAndreas Gohr            }
1320b3fd2d3SAndreas Gohr
1330b3fd2d3SAndreas Gohr            return;
1340b3fd2d3SAndreas Gohr        }
1350b3fd2d3SAndreas Gohr
1360b3fd2d3SAndreas Gohr        $first = $prefix[0];
1370b3fd2d3SAndreas Gohr        if (!isset($this->prefixesPsr0[$first][$prefix])) {
1380b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
1390b3fd2d3SAndreas Gohr
1400b3fd2d3SAndreas Gohr            return;
1410b3fd2d3SAndreas Gohr        }
1420b3fd2d3SAndreas Gohr        if ($prepend) {
1430b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = array_merge(
1440b3fd2d3SAndreas Gohr                (array) $paths,
1450b3fd2d3SAndreas Gohr                $this->prefixesPsr0[$first][$prefix]
1460b3fd2d3SAndreas Gohr            );
1470b3fd2d3SAndreas Gohr        } else {
1480b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = array_merge(
1490b3fd2d3SAndreas Gohr                $this->prefixesPsr0[$first][$prefix],
1500b3fd2d3SAndreas Gohr                (array) $paths
1510b3fd2d3SAndreas Gohr            );
1520b3fd2d3SAndreas Gohr        }
1530b3fd2d3SAndreas Gohr    }
1540b3fd2d3SAndreas Gohr
1550b3fd2d3SAndreas Gohr    /**
1560b3fd2d3SAndreas Gohr     * Registers a set of PSR-4 directories for a given namespace, either
1570b3fd2d3SAndreas Gohr     * appending or prepending to the ones previously set for this namespace.
1580b3fd2d3SAndreas Gohr     *
1590b3fd2d3SAndreas Gohr     * @param string       $prefix  The prefix/namespace, with trailing '\\'
1600b3fd2d3SAndreas Gohr     * @param array|string $paths   The PSR-4 base directories
1610b3fd2d3SAndreas Gohr     * @param bool         $prepend Whether to prepend the directories
1620b3fd2d3SAndreas Gohr     *
1630b3fd2d3SAndreas Gohr     * @throws \InvalidArgumentException
1640b3fd2d3SAndreas Gohr     */
1650b3fd2d3SAndreas Gohr    public function addPsr4($prefix, $paths, $prepend = false)
1660b3fd2d3SAndreas Gohr    {
1670b3fd2d3SAndreas Gohr        if (!$prefix) {
1680b3fd2d3SAndreas Gohr            // Register directories for the root namespace.
1690b3fd2d3SAndreas Gohr            if ($prepend) {
1700b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr4 = array_merge(
1710b3fd2d3SAndreas Gohr                    (array) $paths,
1720b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr4
1730b3fd2d3SAndreas Gohr                );
1740b3fd2d3SAndreas Gohr            } else {
1750b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr4 = array_merge(
1760b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr4,
1770b3fd2d3SAndreas Gohr                    (array) $paths
1780b3fd2d3SAndreas Gohr                );
1790b3fd2d3SAndreas Gohr            }
1800b3fd2d3SAndreas Gohr        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
1810b3fd2d3SAndreas Gohr            // Register directories for a new namespace.
1820b3fd2d3SAndreas Gohr            $length = strlen($prefix);
1830b3fd2d3SAndreas Gohr            if ('\\' !== $prefix[$length - 1]) {
1840b3fd2d3SAndreas Gohr                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
1850b3fd2d3SAndreas Gohr            }
1860b3fd2d3SAndreas Gohr            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
1870b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = (array) $paths;
1880b3fd2d3SAndreas Gohr        } elseif ($prepend) {
1890b3fd2d3SAndreas Gohr            // Prepend directories for an already registered namespace.
1900b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = array_merge(
1910b3fd2d3SAndreas Gohr                (array) $paths,
1920b3fd2d3SAndreas Gohr                $this->prefixDirsPsr4[$prefix]
1930b3fd2d3SAndreas Gohr            );
1940b3fd2d3SAndreas Gohr        } else {
1950b3fd2d3SAndreas Gohr            // Append directories for an already registered namespace.
1960b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = array_merge(
1970b3fd2d3SAndreas Gohr                $this->prefixDirsPsr4[$prefix],
1980b3fd2d3SAndreas Gohr                (array) $paths
1990b3fd2d3SAndreas Gohr            );
2000b3fd2d3SAndreas Gohr        }
2010b3fd2d3SAndreas Gohr    }
2020b3fd2d3SAndreas Gohr
2030b3fd2d3SAndreas Gohr    /**
2040b3fd2d3SAndreas Gohr     * Registers a set of PSR-0 directories for a given prefix,
2050b3fd2d3SAndreas Gohr     * replacing any others previously set for this prefix.
2060b3fd2d3SAndreas Gohr     *
2070b3fd2d3SAndreas Gohr     * @param string       $prefix The prefix
2080b3fd2d3SAndreas Gohr     * @param array|string $paths  The PSR-0 base directories
2090b3fd2d3SAndreas Gohr     */
2100b3fd2d3SAndreas Gohr    public function set($prefix, $paths)
2110b3fd2d3SAndreas Gohr    {
2120b3fd2d3SAndreas Gohr        if (!$prefix) {
2130b3fd2d3SAndreas Gohr            $this->fallbackDirsPsr0 = (array) $paths;
2140b3fd2d3SAndreas Gohr        } else {
2150b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
2160b3fd2d3SAndreas Gohr        }
2170b3fd2d3SAndreas Gohr    }
2180b3fd2d3SAndreas Gohr
2190b3fd2d3SAndreas Gohr    /**
2200b3fd2d3SAndreas Gohr     * Registers a set of PSR-4 directories for a given namespace,
2210b3fd2d3SAndreas Gohr     * replacing any others previously set for this namespace.
2220b3fd2d3SAndreas Gohr     *
2230b3fd2d3SAndreas Gohr     * @param string       $prefix The prefix/namespace, with trailing '\\'
2240b3fd2d3SAndreas Gohr     * @param array|string $paths  The PSR-4 base directories
2250b3fd2d3SAndreas Gohr     *
2260b3fd2d3SAndreas Gohr     * @throws \InvalidArgumentException
2270b3fd2d3SAndreas Gohr     */
2280b3fd2d3SAndreas Gohr    public function setPsr4($prefix, $paths)
2290b3fd2d3SAndreas Gohr    {
2300b3fd2d3SAndreas Gohr        if (!$prefix) {
2310b3fd2d3SAndreas Gohr            $this->fallbackDirsPsr4 = (array) $paths;
2320b3fd2d3SAndreas Gohr        } else {
2330b3fd2d3SAndreas Gohr            $length = strlen($prefix);
2340b3fd2d3SAndreas Gohr            if ('\\' !== $prefix[$length - 1]) {
2350b3fd2d3SAndreas Gohr                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
2360b3fd2d3SAndreas Gohr            }
2370b3fd2d3SAndreas Gohr            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
2380b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = (array) $paths;
2390b3fd2d3SAndreas Gohr        }
2400b3fd2d3SAndreas Gohr    }
2410b3fd2d3SAndreas Gohr
2420b3fd2d3SAndreas Gohr    /**
2430b3fd2d3SAndreas Gohr     * Turns on searching the include path for class files.
2440b3fd2d3SAndreas Gohr     *
2450b3fd2d3SAndreas Gohr     * @param bool $useIncludePath
2460b3fd2d3SAndreas Gohr     */
2470b3fd2d3SAndreas Gohr    public function setUseIncludePath($useIncludePath)
2480b3fd2d3SAndreas Gohr    {
2490b3fd2d3SAndreas Gohr        $this->useIncludePath = $useIncludePath;
2500b3fd2d3SAndreas Gohr    }
2510b3fd2d3SAndreas Gohr
2520b3fd2d3SAndreas Gohr    /**
2530b3fd2d3SAndreas Gohr     * Can be used to check if the autoloader uses the include path to check
2540b3fd2d3SAndreas Gohr     * for classes.
2550b3fd2d3SAndreas Gohr     *
2560b3fd2d3SAndreas Gohr     * @return bool
2570b3fd2d3SAndreas Gohr     */
2580b3fd2d3SAndreas Gohr    public function getUseIncludePath()
2590b3fd2d3SAndreas Gohr    {
2600b3fd2d3SAndreas Gohr        return $this->useIncludePath;
2610b3fd2d3SAndreas Gohr    }
2620b3fd2d3SAndreas Gohr
2630b3fd2d3SAndreas Gohr    /**
2640b3fd2d3SAndreas Gohr     * Turns off searching the prefix and fallback directories for classes
2650b3fd2d3SAndreas Gohr     * that have not been registered with the class map.
2660b3fd2d3SAndreas Gohr     *
2670b3fd2d3SAndreas Gohr     * @param bool $classMapAuthoritative
2680b3fd2d3SAndreas Gohr     */
2690b3fd2d3SAndreas Gohr    public function setClassMapAuthoritative($classMapAuthoritative)
2700b3fd2d3SAndreas Gohr    {
2710b3fd2d3SAndreas Gohr        $this->classMapAuthoritative = $classMapAuthoritative;
2720b3fd2d3SAndreas Gohr    }
2730b3fd2d3SAndreas Gohr
2740b3fd2d3SAndreas Gohr    /**
2750b3fd2d3SAndreas Gohr     * Should class lookup fail if not found in the current class map?
2760b3fd2d3SAndreas Gohr     *
2770b3fd2d3SAndreas Gohr     * @return bool
2780b3fd2d3SAndreas Gohr     */
2790b3fd2d3SAndreas Gohr    public function isClassMapAuthoritative()
2800b3fd2d3SAndreas Gohr    {
2810b3fd2d3SAndreas Gohr        return $this->classMapAuthoritative;
2820b3fd2d3SAndreas Gohr    }
2830b3fd2d3SAndreas Gohr
2840b3fd2d3SAndreas Gohr    /**
2850b3fd2d3SAndreas Gohr     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
2860b3fd2d3SAndreas Gohr     *
2870b3fd2d3SAndreas Gohr     * @param string|null $apcuPrefix
2880b3fd2d3SAndreas Gohr     */
2890b3fd2d3SAndreas Gohr    public function setApcuPrefix($apcuPrefix)
2900b3fd2d3SAndreas Gohr    {
2910b3fd2d3SAndreas Gohr        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
2920b3fd2d3SAndreas Gohr    }
2930b3fd2d3SAndreas Gohr
2940b3fd2d3SAndreas Gohr    /**
2950b3fd2d3SAndreas Gohr     * The APCu prefix in use, or null if APCu caching is not enabled.
2960b3fd2d3SAndreas Gohr     *
2970b3fd2d3SAndreas Gohr     * @return string|null
2980b3fd2d3SAndreas Gohr     */
2990b3fd2d3SAndreas Gohr    public function getApcuPrefix()
3000b3fd2d3SAndreas Gohr    {
3010b3fd2d3SAndreas Gohr        return $this->apcuPrefix;
3020b3fd2d3SAndreas Gohr    }
3030b3fd2d3SAndreas Gohr
3040b3fd2d3SAndreas Gohr    /**
3050b3fd2d3SAndreas Gohr     * Registers this instance as an autoloader.
3060b3fd2d3SAndreas Gohr     *
3070b3fd2d3SAndreas Gohr     * @param bool $prepend Whether to prepend the autoloader or not
3080b3fd2d3SAndreas Gohr     */
3090b3fd2d3SAndreas Gohr    public function register($prepend = false)
3100b3fd2d3SAndreas Gohr    {
3110b3fd2d3SAndreas Gohr        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
312*fd0855ecSAndreas Gohr
313*fd0855ecSAndreas Gohr        if (null === $this->vendorDir) {
314*fd0855ecSAndreas Gohr            return;
315*fd0855ecSAndreas Gohr        }
316*fd0855ecSAndreas Gohr
317*fd0855ecSAndreas Gohr        if ($prepend) {
318*fd0855ecSAndreas Gohr            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
319*fd0855ecSAndreas Gohr        } else {
320*fd0855ecSAndreas Gohr            unset(self::$registeredLoaders[$this->vendorDir]);
321*fd0855ecSAndreas Gohr            self::$registeredLoaders[$this->vendorDir] = $this;
322*fd0855ecSAndreas Gohr        }
3230b3fd2d3SAndreas Gohr    }
3240b3fd2d3SAndreas Gohr
3250b3fd2d3SAndreas Gohr    /**
3260b3fd2d3SAndreas Gohr     * Unregisters this instance as an autoloader.
3270b3fd2d3SAndreas Gohr     */
3280b3fd2d3SAndreas Gohr    public function unregister()
3290b3fd2d3SAndreas Gohr    {
3300b3fd2d3SAndreas Gohr        spl_autoload_unregister(array($this, 'loadClass'));
331*fd0855ecSAndreas Gohr
332*fd0855ecSAndreas Gohr        if (null !== $this->vendorDir) {
333*fd0855ecSAndreas Gohr            unset(self::$registeredLoaders[$this->vendorDir]);
334*fd0855ecSAndreas Gohr        }
3350b3fd2d3SAndreas Gohr    }
3360b3fd2d3SAndreas Gohr
3370b3fd2d3SAndreas Gohr    /**
3380b3fd2d3SAndreas Gohr     * Loads the given class or interface.
3390b3fd2d3SAndreas Gohr     *
3400b3fd2d3SAndreas Gohr     * @param  string    $class The name of the class
341*fd0855ecSAndreas Gohr     * @return true|null True if loaded, null otherwise
3420b3fd2d3SAndreas Gohr     */
3430b3fd2d3SAndreas Gohr    public function loadClass($class)
3440b3fd2d3SAndreas Gohr    {
3450b3fd2d3SAndreas Gohr        if ($file = $this->findFile($class)) {
3460b3fd2d3SAndreas Gohr            includeFile($file);
3470b3fd2d3SAndreas Gohr
3480b3fd2d3SAndreas Gohr            return true;
3490b3fd2d3SAndreas Gohr        }
350*fd0855ecSAndreas Gohr
351*fd0855ecSAndreas Gohr        return null;
3520b3fd2d3SAndreas Gohr    }
3530b3fd2d3SAndreas Gohr
3540b3fd2d3SAndreas Gohr    /**
3550b3fd2d3SAndreas Gohr     * Finds the path to the file where the class is defined.
3560b3fd2d3SAndreas Gohr     *
3570b3fd2d3SAndreas Gohr     * @param string $class The name of the class
3580b3fd2d3SAndreas Gohr     *
3590b3fd2d3SAndreas Gohr     * @return string|false The path if found, false otherwise
3600b3fd2d3SAndreas Gohr     */
3610b3fd2d3SAndreas Gohr    public function findFile($class)
3620b3fd2d3SAndreas Gohr    {
3630b3fd2d3SAndreas Gohr        // class map lookup
3640b3fd2d3SAndreas Gohr        if (isset($this->classMap[$class])) {
3650b3fd2d3SAndreas Gohr            return $this->classMap[$class];
3660b3fd2d3SAndreas Gohr        }
3670b3fd2d3SAndreas Gohr        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
3680b3fd2d3SAndreas Gohr            return false;
3690b3fd2d3SAndreas Gohr        }
3700b3fd2d3SAndreas Gohr        if (null !== $this->apcuPrefix) {
3710b3fd2d3SAndreas Gohr            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
3720b3fd2d3SAndreas Gohr            if ($hit) {
3730b3fd2d3SAndreas Gohr                return $file;
3740b3fd2d3SAndreas Gohr            }
3750b3fd2d3SAndreas Gohr        }
3760b3fd2d3SAndreas Gohr
3770b3fd2d3SAndreas Gohr        $file = $this->findFileWithExtension($class, '.php');
3780b3fd2d3SAndreas Gohr
3790b3fd2d3SAndreas Gohr        // Search for Hack files if we are running on HHVM
3800b3fd2d3SAndreas Gohr        if (false === $file && defined('HHVM_VERSION')) {
3810b3fd2d3SAndreas Gohr            $file = $this->findFileWithExtension($class, '.hh');
3820b3fd2d3SAndreas Gohr        }
3830b3fd2d3SAndreas Gohr
3840b3fd2d3SAndreas Gohr        if (null !== $this->apcuPrefix) {
3850b3fd2d3SAndreas Gohr            apcu_add($this->apcuPrefix.$class, $file);
3860b3fd2d3SAndreas Gohr        }
3870b3fd2d3SAndreas Gohr
3880b3fd2d3SAndreas Gohr        if (false === $file) {
3890b3fd2d3SAndreas Gohr            // Remember that this class does not exist.
3900b3fd2d3SAndreas Gohr            $this->missingClasses[$class] = true;
3910b3fd2d3SAndreas Gohr        }
3920b3fd2d3SAndreas Gohr
3930b3fd2d3SAndreas Gohr        return $file;
3940b3fd2d3SAndreas Gohr    }
3950b3fd2d3SAndreas Gohr
396*fd0855ecSAndreas Gohr    /**
397*fd0855ecSAndreas Gohr     * Returns the currently registered loaders indexed by their corresponding vendor directories.
398*fd0855ecSAndreas Gohr     *
399*fd0855ecSAndreas Gohr     * @return self[]
400*fd0855ecSAndreas Gohr     */
401*fd0855ecSAndreas Gohr    public static function getRegisteredLoaders()
402*fd0855ecSAndreas Gohr    {
403*fd0855ecSAndreas Gohr        return self::$registeredLoaders;
404*fd0855ecSAndreas Gohr    }
405*fd0855ecSAndreas Gohr
4060b3fd2d3SAndreas Gohr    private function findFileWithExtension($class, $ext)
4070b3fd2d3SAndreas Gohr    {
4080b3fd2d3SAndreas Gohr        // PSR-4 lookup
4090b3fd2d3SAndreas Gohr        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
4100b3fd2d3SAndreas Gohr
4110b3fd2d3SAndreas Gohr        $first = $class[0];
4120b3fd2d3SAndreas Gohr        if (isset($this->prefixLengthsPsr4[$first])) {
4130b3fd2d3SAndreas Gohr            $subPath = $class;
4140b3fd2d3SAndreas Gohr            while (false !== $lastPos = strrpos($subPath, '\\')) {
4150b3fd2d3SAndreas Gohr                $subPath = substr($subPath, 0, $lastPos);
4160b3fd2d3SAndreas Gohr                $search = $subPath . '\\';
4170b3fd2d3SAndreas Gohr                if (isset($this->prefixDirsPsr4[$search])) {
4180b3fd2d3SAndreas Gohr                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
4190b3fd2d3SAndreas Gohr                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
4200b3fd2d3SAndreas Gohr                        if (file_exists($file = $dir . $pathEnd)) {
4210b3fd2d3SAndreas Gohr                            return $file;
4220b3fd2d3SAndreas Gohr                        }
4230b3fd2d3SAndreas Gohr                    }
4240b3fd2d3SAndreas Gohr                }
4250b3fd2d3SAndreas Gohr            }
4260b3fd2d3SAndreas Gohr        }
4270b3fd2d3SAndreas Gohr
4280b3fd2d3SAndreas Gohr        // PSR-4 fallback dirs
4290b3fd2d3SAndreas Gohr        foreach ($this->fallbackDirsPsr4 as $dir) {
4300b3fd2d3SAndreas Gohr            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
4310b3fd2d3SAndreas Gohr                return $file;
4320b3fd2d3SAndreas Gohr            }
4330b3fd2d3SAndreas Gohr        }
4340b3fd2d3SAndreas Gohr
4350b3fd2d3SAndreas Gohr        // PSR-0 lookup
4360b3fd2d3SAndreas Gohr        if (false !== $pos = strrpos($class, '\\')) {
4370b3fd2d3SAndreas Gohr            // namespaced class name
4380b3fd2d3SAndreas Gohr            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
4390b3fd2d3SAndreas Gohr                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
4400b3fd2d3SAndreas Gohr        } else {
4410b3fd2d3SAndreas Gohr            // PEAR-like class name
4420b3fd2d3SAndreas Gohr            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
4430b3fd2d3SAndreas Gohr        }
4440b3fd2d3SAndreas Gohr
4450b3fd2d3SAndreas Gohr        if (isset($this->prefixesPsr0[$first])) {
4460b3fd2d3SAndreas Gohr            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
4470b3fd2d3SAndreas Gohr                if (0 === strpos($class, $prefix)) {
4480b3fd2d3SAndreas Gohr                    foreach ($dirs as $dir) {
4490b3fd2d3SAndreas Gohr                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
4500b3fd2d3SAndreas Gohr                            return $file;
4510b3fd2d3SAndreas Gohr                        }
4520b3fd2d3SAndreas Gohr                    }
4530b3fd2d3SAndreas Gohr                }
4540b3fd2d3SAndreas Gohr            }
4550b3fd2d3SAndreas Gohr        }
4560b3fd2d3SAndreas Gohr
4570b3fd2d3SAndreas Gohr        // PSR-0 fallback dirs
4580b3fd2d3SAndreas Gohr        foreach ($this->fallbackDirsPsr0 as $dir) {
4590b3fd2d3SAndreas Gohr            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
4600b3fd2d3SAndreas Gohr                return $file;
4610b3fd2d3SAndreas Gohr            }
4620b3fd2d3SAndreas Gohr        }
4630b3fd2d3SAndreas Gohr
4640b3fd2d3SAndreas Gohr        // PSR-0 include paths.
4650b3fd2d3SAndreas Gohr        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
4660b3fd2d3SAndreas Gohr            return $file;
4670b3fd2d3SAndreas Gohr        }
4680b3fd2d3SAndreas Gohr
4690b3fd2d3SAndreas Gohr        return false;
4700b3fd2d3SAndreas Gohr    }
4710b3fd2d3SAndreas Gohr}
4720b3fd2d3SAndreas Gohr
4730b3fd2d3SAndreas Gohr/**
4740b3fd2d3SAndreas Gohr * Scope isolated include.
4750b3fd2d3SAndreas Gohr *
4760b3fd2d3SAndreas Gohr * Prevents access to $this/self from included files.
4770b3fd2d3SAndreas Gohr */
4780b3fd2d3SAndreas Gohrfunction includeFile($file)
4790b3fd2d3SAndreas Gohr{
4800b3fd2d3SAndreas Gohr    include $file;
4810b3fd2d3SAndreas Gohr}
482