xref: /plugin/pureldap/vendor/composer/ClassLoader.php (revision 0b3fd2d31e4d1997548a8fbc53fa771027c4a47f)
1*0b3fd2d3SAndreas Gohr<?php
2*0b3fd2d3SAndreas Gohr
3*0b3fd2d3SAndreas Gohr/*
4*0b3fd2d3SAndreas Gohr * This file is part of Composer.
5*0b3fd2d3SAndreas Gohr *
6*0b3fd2d3SAndreas Gohr * (c) Nils Adermann <naderman@naderman.de>
7*0b3fd2d3SAndreas Gohr *     Jordi Boggiano <j.boggiano@seld.be>
8*0b3fd2d3SAndreas Gohr *
9*0b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE
10*0b3fd2d3SAndreas Gohr * file that was distributed with this source code.
11*0b3fd2d3SAndreas Gohr */
12*0b3fd2d3SAndreas Gohr
13*0b3fd2d3SAndreas Gohrnamespace Composer\Autoload;
14*0b3fd2d3SAndreas Gohr
15*0b3fd2d3SAndreas Gohr/**
16*0b3fd2d3SAndreas Gohr * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17*0b3fd2d3SAndreas Gohr *
18*0b3fd2d3SAndreas Gohr *     $loader = new \Composer\Autoload\ClassLoader();
19*0b3fd2d3SAndreas Gohr *
20*0b3fd2d3SAndreas Gohr *     // register classes with namespaces
21*0b3fd2d3SAndreas Gohr *     $loader->add('Symfony\Component', __DIR__.'/component');
22*0b3fd2d3SAndreas Gohr *     $loader->add('Symfony',           __DIR__.'/framework');
23*0b3fd2d3SAndreas Gohr *
24*0b3fd2d3SAndreas Gohr *     // activate the autoloader
25*0b3fd2d3SAndreas Gohr *     $loader->register();
26*0b3fd2d3SAndreas Gohr *
27*0b3fd2d3SAndreas Gohr *     // to enable searching the include path (eg. for PEAR packages)
28*0b3fd2d3SAndreas Gohr *     $loader->setUseIncludePath(true);
29*0b3fd2d3SAndreas Gohr *
30*0b3fd2d3SAndreas Gohr * In this example, if you try to use a class in the Symfony\Component
31*0b3fd2d3SAndreas Gohr * namespace or one of its children (Symfony\Component\Console for instance),
32*0b3fd2d3SAndreas Gohr * the autoloader will first look for the class under the component/
33*0b3fd2d3SAndreas Gohr * directory, and it will then fallback to the framework/ directory if not
34*0b3fd2d3SAndreas Gohr * found before giving up.
35*0b3fd2d3SAndreas Gohr *
36*0b3fd2d3SAndreas Gohr * This class is loosely based on the Symfony UniversalClassLoader.
37*0b3fd2d3SAndreas Gohr *
38*0b3fd2d3SAndreas Gohr * @author Fabien Potencier <fabien@symfony.com>
39*0b3fd2d3SAndreas Gohr * @author Jordi Boggiano <j.boggiano@seld.be>
40*0b3fd2d3SAndreas Gohr * @see    http://www.php-fig.org/psr/psr-0/
41*0b3fd2d3SAndreas Gohr * @see    http://www.php-fig.org/psr/psr-4/
42*0b3fd2d3SAndreas Gohr */
43*0b3fd2d3SAndreas Gohrclass ClassLoader
44*0b3fd2d3SAndreas Gohr{
45*0b3fd2d3SAndreas Gohr    // PSR-4
46*0b3fd2d3SAndreas Gohr    private $prefixLengthsPsr4 = array();
47*0b3fd2d3SAndreas Gohr    private $prefixDirsPsr4 = array();
48*0b3fd2d3SAndreas Gohr    private $fallbackDirsPsr4 = array();
49*0b3fd2d3SAndreas Gohr
50*0b3fd2d3SAndreas Gohr    // PSR-0
51*0b3fd2d3SAndreas Gohr    private $prefixesPsr0 = array();
52*0b3fd2d3SAndreas Gohr    private $fallbackDirsPsr0 = array();
53*0b3fd2d3SAndreas Gohr
54*0b3fd2d3SAndreas Gohr    private $useIncludePath = false;
55*0b3fd2d3SAndreas Gohr    private $classMap = array();
56*0b3fd2d3SAndreas Gohr    private $classMapAuthoritative = false;
57*0b3fd2d3SAndreas Gohr    private $missingClasses = array();
58*0b3fd2d3SAndreas Gohr    private $apcuPrefix;
59*0b3fd2d3SAndreas Gohr
60*0b3fd2d3SAndreas Gohr    public function getPrefixes()
61*0b3fd2d3SAndreas Gohr    {
62*0b3fd2d3SAndreas Gohr        if (!empty($this->prefixesPsr0)) {
63*0b3fd2d3SAndreas Gohr            return call_user_func_array('array_merge', $this->prefixesPsr0);
64*0b3fd2d3SAndreas Gohr        }
65*0b3fd2d3SAndreas Gohr
66*0b3fd2d3SAndreas Gohr        return array();
67*0b3fd2d3SAndreas Gohr    }
68*0b3fd2d3SAndreas Gohr
69*0b3fd2d3SAndreas Gohr    public function getPrefixesPsr4()
70*0b3fd2d3SAndreas Gohr    {
71*0b3fd2d3SAndreas Gohr        return $this->prefixDirsPsr4;
72*0b3fd2d3SAndreas Gohr    }
73*0b3fd2d3SAndreas Gohr
74*0b3fd2d3SAndreas Gohr    public function getFallbackDirs()
75*0b3fd2d3SAndreas Gohr    {
76*0b3fd2d3SAndreas Gohr        return $this->fallbackDirsPsr0;
77*0b3fd2d3SAndreas Gohr    }
78*0b3fd2d3SAndreas Gohr
79*0b3fd2d3SAndreas Gohr    public function getFallbackDirsPsr4()
80*0b3fd2d3SAndreas Gohr    {
81*0b3fd2d3SAndreas Gohr        return $this->fallbackDirsPsr4;
82*0b3fd2d3SAndreas Gohr    }
83*0b3fd2d3SAndreas Gohr
84*0b3fd2d3SAndreas Gohr    public function getClassMap()
85*0b3fd2d3SAndreas Gohr    {
86*0b3fd2d3SAndreas Gohr        return $this->classMap;
87*0b3fd2d3SAndreas Gohr    }
88*0b3fd2d3SAndreas Gohr
89*0b3fd2d3SAndreas Gohr    /**
90*0b3fd2d3SAndreas Gohr     * @param array $classMap Class to filename map
91*0b3fd2d3SAndreas Gohr     */
92*0b3fd2d3SAndreas Gohr    public function addClassMap(array $classMap)
93*0b3fd2d3SAndreas Gohr    {
94*0b3fd2d3SAndreas Gohr        if ($this->classMap) {
95*0b3fd2d3SAndreas Gohr            $this->classMap = array_merge($this->classMap, $classMap);
96*0b3fd2d3SAndreas Gohr        } else {
97*0b3fd2d3SAndreas Gohr            $this->classMap = $classMap;
98*0b3fd2d3SAndreas Gohr        }
99*0b3fd2d3SAndreas Gohr    }
100*0b3fd2d3SAndreas Gohr
101*0b3fd2d3SAndreas Gohr    /**
102*0b3fd2d3SAndreas Gohr     * Registers a set of PSR-0 directories for a given prefix, either
103*0b3fd2d3SAndreas Gohr     * appending or prepending to the ones previously set for this prefix.
104*0b3fd2d3SAndreas Gohr     *
105*0b3fd2d3SAndreas Gohr     * @param string       $prefix  The prefix
106*0b3fd2d3SAndreas Gohr     * @param array|string $paths   The PSR-0 root directories
107*0b3fd2d3SAndreas Gohr     * @param bool         $prepend Whether to prepend the directories
108*0b3fd2d3SAndreas Gohr     */
109*0b3fd2d3SAndreas Gohr    public function add($prefix, $paths, $prepend = false)
110*0b3fd2d3SAndreas Gohr    {
111*0b3fd2d3SAndreas Gohr        if (!$prefix) {
112*0b3fd2d3SAndreas Gohr            if ($prepend) {
113*0b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr0 = array_merge(
114*0b3fd2d3SAndreas Gohr                    (array) $paths,
115*0b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr0
116*0b3fd2d3SAndreas Gohr                );
117*0b3fd2d3SAndreas Gohr            } else {
118*0b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr0 = array_merge(
119*0b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr0,
120*0b3fd2d3SAndreas Gohr                    (array) $paths
121*0b3fd2d3SAndreas Gohr                );
122*0b3fd2d3SAndreas Gohr            }
123*0b3fd2d3SAndreas Gohr
124*0b3fd2d3SAndreas Gohr            return;
125*0b3fd2d3SAndreas Gohr        }
126*0b3fd2d3SAndreas Gohr
127*0b3fd2d3SAndreas Gohr        $first = $prefix[0];
128*0b3fd2d3SAndreas Gohr        if (!isset($this->prefixesPsr0[$first][$prefix])) {
129*0b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130*0b3fd2d3SAndreas Gohr
131*0b3fd2d3SAndreas Gohr            return;
132*0b3fd2d3SAndreas Gohr        }
133*0b3fd2d3SAndreas Gohr        if ($prepend) {
134*0b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = array_merge(
135*0b3fd2d3SAndreas Gohr                (array) $paths,
136*0b3fd2d3SAndreas Gohr                $this->prefixesPsr0[$first][$prefix]
137*0b3fd2d3SAndreas Gohr            );
138*0b3fd2d3SAndreas Gohr        } else {
139*0b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$first][$prefix] = array_merge(
140*0b3fd2d3SAndreas Gohr                $this->prefixesPsr0[$first][$prefix],
141*0b3fd2d3SAndreas Gohr                (array) $paths
142*0b3fd2d3SAndreas Gohr            );
143*0b3fd2d3SAndreas Gohr        }
144*0b3fd2d3SAndreas Gohr    }
145*0b3fd2d3SAndreas Gohr
146*0b3fd2d3SAndreas Gohr    /**
147*0b3fd2d3SAndreas Gohr     * Registers a set of PSR-4 directories for a given namespace, either
148*0b3fd2d3SAndreas Gohr     * appending or prepending to the ones previously set for this namespace.
149*0b3fd2d3SAndreas Gohr     *
150*0b3fd2d3SAndreas Gohr     * @param string       $prefix  The prefix/namespace, with trailing '\\'
151*0b3fd2d3SAndreas Gohr     * @param array|string $paths   The PSR-4 base directories
152*0b3fd2d3SAndreas Gohr     * @param bool         $prepend Whether to prepend the directories
153*0b3fd2d3SAndreas Gohr     *
154*0b3fd2d3SAndreas Gohr     * @throws \InvalidArgumentException
155*0b3fd2d3SAndreas Gohr     */
156*0b3fd2d3SAndreas Gohr    public function addPsr4($prefix, $paths, $prepend = false)
157*0b3fd2d3SAndreas Gohr    {
158*0b3fd2d3SAndreas Gohr        if (!$prefix) {
159*0b3fd2d3SAndreas Gohr            // Register directories for the root namespace.
160*0b3fd2d3SAndreas Gohr            if ($prepend) {
161*0b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr4 = array_merge(
162*0b3fd2d3SAndreas Gohr                    (array) $paths,
163*0b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr4
164*0b3fd2d3SAndreas Gohr                );
165*0b3fd2d3SAndreas Gohr            } else {
166*0b3fd2d3SAndreas Gohr                $this->fallbackDirsPsr4 = array_merge(
167*0b3fd2d3SAndreas Gohr                    $this->fallbackDirsPsr4,
168*0b3fd2d3SAndreas Gohr                    (array) $paths
169*0b3fd2d3SAndreas Gohr                );
170*0b3fd2d3SAndreas Gohr            }
171*0b3fd2d3SAndreas Gohr        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172*0b3fd2d3SAndreas Gohr            // Register directories for a new namespace.
173*0b3fd2d3SAndreas Gohr            $length = strlen($prefix);
174*0b3fd2d3SAndreas Gohr            if ('\\' !== $prefix[$length - 1]) {
175*0b3fd2d3SAndreas Gohr                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176*0b3fd2d3SAndreas Gohr            }
177*0b3fd2d3SAndreas Gohr            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178*0b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = (array) $paths;
179*0b3fd2d3SAndreas Gohr        } elseif ($prepend) {
180*0b3fd2d3SAndreas Gohr            // Prepend directories for an already registered namespace.
181*0b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = array_merge(
182*0b3fd2d3SAndreas Gohr                (array) $paths,
183*0b3fd2d3SAndreas Gohr                $this->prefixDirsPsr4[$prefix]
184*0b3fd2d3SAndreas Gohr            );
185*0b3fd2d3SAndreas Gohr        } else {
186*0b3fd2d3SAndreas Gohr            // Append directories for an already registered namespace.
187*0b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = array_merge(
188*0b3fd2d3SAndreas Gohr                $this->prefixDirsPsr4[$prefix],
189*0b3fd2d3SAndreas Gohr                (array) $paths
190*0b3fd2d3SAndreas Gohr            );
191*0b3fd2d3SAndreas Gohr        }
192*0b3fd2d3SAndreas Gohr    }
193*0b3fd2d3SAndreas Gohr
194*0b3fd2d3SAndreas Gohr    /**
195*0b3fd2d3SAndreas Gohr     * Registers a set of PSR-0 directories for a given prefix,
196*0b3fd2d3SAndreas Gohr     * replacing any others previously set for this prefix.
197*0b3fd2d3SAndreas Gohr     *
198*0b3fd2d3SAndreas Gohr     * @param string       $prefix The prefix
199*0b3fd2d3SAndreas Gohr     * @param array|string $paths  The PSR-0 base directories
200*0b3fd2d3SAndreas Gohr     */
201*0b3fd2d3SAndreas Gohr    public function set($prefix, $paths)
202*0b3fd2d3SAndreas Gohr    {
203*0b3fd2d3SAndreas Gohr        if (!$prefix) {
204*0b3fd2d3SAndreas Gohr            $this->fallbackDirsPsr0 = (array) $paths;
205*0b3fd2d3SAndreas Gohr        } else {
206*0b3fd2d3SAndreas Gohr            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207*0b3fd2d3SAndreas Gohr        }
208*0b3fd2d3SAndreas Gohr    }
209*0b3fd2d3SAndreas Gohr
210*0b3fd2d3SAndreas Gohr    /**
211*0b3fd2d3SAndreas Gohr     * Registers a set of PSR-4 directories for a given namespace,
212*0b3fd2d3SAndreas Gohr     * replacing any others previously set for this namespace.
213*0b3fd2d3SAndreas Gohr     *
214*0b3fd2d3SAndreas Gohr     * @param string       $prefix The prefix/namespace, with trailing '\\'
215*0b3fd2d3SAndreas Gohr     * @param array|string $paths  The PSR-4 base directories
216*0b3fd2d3SAndreas Gohr     *
217*0b3fd2d3SAndreas Gohr     * @throws \InvalidArgumentException
218*0b3fd2d3SAndreas Gohr     */
219*0b3fd2d3SAndreas Gohr    public function setPsr4($prefix, $paths)
220*0b3fd2d3SAndreas Gohr    {
221*0b3fd2d3SAndreas Gohr        if (!$prefix) {
222*0b3fd2d3SAndreas Gohr            $this->fallbackDirsPsr4 = (array) $paths;
223*0b3fd2d3SAndreas Gohr        } else {
224*0b3fd2d3SAndreas Gohr            $length = strlen($prefix);
225*0b3fd2d3SAndreas Gohr            if ('\\' !== $prefix[$length - 1]) {
226*0b3fd2d3SAndreas Gohr                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227*0b3fd2d3SAndreas Gohr            }
228*0b3fd2d3SAndreas Gohr            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229*0b3fd2d3SAndreas Gohr            $this->prefixDirsPsr4[$prefix] = (array) $paths;
230*0b3fd2d3SAndreas Gohr        }
231*0b3fd2d3SAndreas Gohr    }
232*0b3fd2d3SAndreas Gohr
233*0b3fd2d3SAndreas Gohr    /**
234*0b3fd2d3SAndreas Gohr     * Turns on searching the include path for class files.
235*0b3fd2d3SAndreas Gohr     *
236*0b3fd2d3SAndreas Gohr     * @param bool $useIncludePath
237*0b3fd2d3SAndreas Gohr     */
238*0b3fd2d3SAndreas Gohr    public function setUseIncludePath($useIncludePath)
239*0b3fd2d3SAndreas Gohr    {
240*0b3fd2d3SAndreas Gohr        $this->useIncludePath = $useIncludePath;
241*0b3fd2d3SAndreas Gohr    }
242*0b3fd2d3SAndreas Gohr
243*0b3fd2d3SAndreas Gohr    /**
244*0b3fd2d3SAndreas Gohr     * Can be used to check if the autoloader uses the include path to check
245*0b3fd2d3SAndreas Gohr     * for classes.
246*0b3fd2d3SAndreas Gohr     *
247*0b3fd2d3SAndreas Gohr     * @return bool
248*0b3fd2d3SAndreas Gohr     */
249*0b3fd2d3SAndreas Gohr    public function getUseIncludePath()
250*0b3fd2d3SAndreas Gohr    {
251*0b3fd2d3SAndreas Gohr        return $this->useIncludePath;
252*0b3fd2d3SAndreas Gohr    }
253*0b3fd2d3SAndreas Gohr
254*0b3fd2d3SAndreas Gohr    /**
255*0b3fd2d3SAndreas Gohr     * Turns off searching the prefix and fallback directories for classes
256*0b3fd2d3SAndreas Gohr     * that have not been registered with the class map.
257*0b3fd2d3SAndreas Gohr     *
258*0b3fd2d3SAndreas Gohr     * @param bool $classMapAuthoritative
259*0b3fd2d3SAndreas Gohr     */
260*0b3fd2d3SAndreas Gohr    public function setClassMapAuthoritative($classMapAuthoritative)
261*0b3fd2d3SAndreas Gohr    {
262*0b3fd2d3SAndreas Gohr        $this->classMapAuthoritative = $classMapAuthoritative;
263*0b3fd2d3SAndreas Gohr    }
264*0b3fd2d3SAndreas Gohr
265*0b3fd2d3SAndreas Gohr    /**
266*0b3fd2d3SAndreas Gohr     * Should class lookup fail if not found in the current class map?
267*0b3fd2d3SAndreas Gohr     *
268*0b3fd2d3SAndreas Gohr     * @return bool
269*0b3fd2d3SAndreas Gohr     */
270*0b3fd2d3SAndreas Gohr    public function isClassMapAuthoritative()
271*0b3fd2d3SAndreas Gohr    {
272*0b3fd2d3SAndreas Gohr        return $this->classMapAuthoritative;
273*0b3fd2d3SAndreas Gohr    }
274*0b3fd2d3SAndreas Gohr
275*0b3fd2d3SAndreas Gohr    /**
276*0b3fd2d3SAndreas Gohr     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277*0b3fd2d3SAndreas Gohr     *
278*0b3fd2d3SAndreas Gohr     * @param string|null $apcuPrefix
279*0b3fd2d3SAndreas Gohr     */
280*0b3fd2d3SAndreas Gohr    public function setApcuPrefix($apcuPrefix)
281*0b3fd2d3SAndreas Gohr    {
282*0b3fd2d3SAndreas Gohr        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283*0b3fd2d3SAndreas Gohr    }
284*0b3fd2d3SAndreas Gohr
285*0b3fd2d3SAndreas Gohr    /**
286*0b3fd2d3SAndreas Gohr     * The APCu prefix in use, or null if APCu caching is not enabled.
287*0b3fd2d3SAndreas Gohr     *
288*0b3fd2d3SAndreas Gohr     * @return string|null
289*0b3fd2d3SAndreas Gohr     */
290*0b3fd2d3SAndreas Gohr    public function getApcuPrefix()
291*0b3fd2d3SAndreas Gohr    {
292*0b3fd2d3SAndreas Gohr        return $this->apcuPrefix;
293*0b3fd2d3SAndreas Gohr    }
294*0b3fd2d3SAndreas Gohr
295*0b3fd2d3SAndreas Gohr    /**
296*0b3fd2d3SAndreas Gohr     * Registers this instance as an autoloader.
297*0b3fd2d3SAndreas Gohr     *
298*0b3fd2d3SAndreas Gohr     * @param bool $prepend Whether to prepend the autoloader or not
299*0b3fd2d3SAndreas Gohr     */
300*0b3fd2d3SAndreas Gohr    public function register($prepend = false)
301*0b3fd2d3SAndreas Gohr    {
302*0b3fd2d3SAndreas Gohr        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303*0b3fd2d3SAndreas Gohr    }
304*0b3fd2d3SAndreas Gohr
305*0b3fd2d3SAndreas Gohr    /**
306*0b3fd2d3SAndreas Gohr     * Unregisters this instance as an autoloader.
307*0b3fd2d3SAndreas Gohr     */
308*0b3fd2d3SAndreas Gohr    public function unregister()
309*0b3fd2d3SAndreas Gohr    {
310*0b3fd2d3SAndreas Gohr        spl_autoload_unregister(array($this, 'loadClass'));
311*0b3fd2d3SAndreas Gohr    }
312*0b3fd2d3SAndreas Gohr
313*0b3fd2d3SAndreas Gohr    /**
314*0b3fd2d3SAndreas Gohr     * Loads the given class or interface.
315*0b3fd2d3SAndreas Gohr     *
316*0b3fd2d3SAndreas Gohr     * @param  string    $class The name of the class
317*0b3fd2d3SAndreas Gohr     * @return bool|null True if loaded, null otherwise
318*0b3fd2d3SAndreas Gohr     */
319*0b3fd2d3SAndreas Gohr    public function loadClass($class)
320*0b3fd2d3SAndreas Gohr    {
321*0b3fd2d3SAndreas Gohr        if ($file = $this->findFile($class)) {
322*0b3fd2d3SAndreas Gohr            includeFile($file);
323*0b3fd2d3SAndreas Gohr
324*0b3fd2d3SAndreas Gohr            return true;
325*0b3fd2d3SAndreas Gohr        }
326*0b3fd2d3SAndreas Gohr    }
327*0b3fd2d3SAndreas Gohr
328*0b3fd2d3SAndreas Gohr    /**
329*0b3fd2d3SAndreas Gohr     * Finds the path to the file where the class is defined.
330*0b3fd2d3SAndreas Gohr     *
331*0b3fd2d3SAndreas Gohr     * @param string $class The name of the class
332*0b3fd2d3SAndreas Gohr     *
333*0b3fd2d3SAndreas Gohr     * @return string|false The path if found, false otherwise
334*0b3fd2d3SAndreas Gohr     */
335*0b3fd2d3SAndreas Gohr    public function findFile($class)
336*0b3fd2d3SAndreas Gohr    {
337*0b3fd2d3SAndreas Gohr        // class map lookup
338*0b3fd2d3SAndreas Gohr        if (isset($this->classMap[$class])) {
339*0b3fd2d3SAndreas Gohr            return $this->classMap[$class];
340*0b3fd2d3SAndreas Gohr        }
341*0b3fd2d3SAndreas Gohr        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342*0b3fd2d3SAndreas Gohr            return false;
343*0b3fd2d3SAndreas Gohr        }
344*0b3fd2d3SAndreas Gohr        if (null !== $this->apcuPrefix) {
345*0b3fd2d3SAndreas Gohr            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346*0b3fd2d3SAndreas Gohr            if ($hit) {
347*0b3fd2d3SAndreas Gohr                return $file;
348*0b3fd2d3SAndreas Gohr            }
349*0b3fd2d3SAndreas Gohr        }
350*0b3fd2d3SAndreas Gohr
351*0b3fd2d3SAndreas Gohr        $file = $this->findFileWithExtension($class, '.php');
352*0b3fd2d3SAndreas Gohr
353*0b3fd2d3SAndreas Gohr        // Search for Hack files if we are running on HHVM
354*0b3fd2d3SAndreas Gohr        if (false === $file && defined('HHVM_VERSION')) {
355*0b3fd2d3SAndreas Gohr            $file = $this->findFileWithExtension($class, '.hh');
356*0b3fd2d3SAndreas Gohr        }
357*0b3fd2d3SAndreas Gohr
358*0b3fd2d3SAndreas Gohr        if (null !== $this->apcuPrefix) {
359*0b3fd2d3SAndreas Gohr            apcu_add($this->apcuPrefix.$class, $file);
360*0b3fd2d3SAndreas Gohr        }
361*0b3fd2d3SAndreas Gohr
362*0b3fd2d3SAndreas Gohr        if (false === $file) {
363*0b3fd2d3SAndreas Gohr            // Remember that this class does not exist.
364*0b3fd2d3SAndreas Gohr            $this->missingClasses[$class] = true;
365*0b3fd2d3SAndreas Gohr        }
366*0b3fd2d3SAndreas Gohr
367*0b3fd2d3SAndreas Gohr        return $file;
368*0b3fd2d3SAndreas Gohr    }
369*0b3fd2d3SAndreas Gohr
370*0b3fd2d3SAndreas Gohr    private function findFileWithExtension($class, $ext)
371*0b3fd2d3SAndreas Gohr    {
372*0b3fd2d3SAndreas Gohr        // PSR-4 lookup
373*0b3fd2d3SAndreas Gohr        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374*0b3fd2d3SAndreas Gohr
375*0b3fd2d3SAndreas Gohr        $first = $class[0];
376*0b3fd2d3SAndreas Gohr        if (isset($this->prefixLengthsPsr4[$first])) {
377*0b3fd2d3SAndreas Gohr            $subPath = $class;
378*0b3fd2d3SAndreas Gohr            while (false !== $lastPos = strrpos($subPath, '\\')) {
379*0b3fd2d3SAndreas Gohr                $subPath = substr($subPath, 0, $lastPos);
380*0b3fd2d3SAndreas Gohr                $search = $subPath . '\\';
381*0b3fd2d3SAndreas Gohr                if (isset($this->prefixDirsPsr4[$search])) {
382*0b3fd2d3SAndreas Gohr                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383*0b3fd2d3SAndreas Gohr                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
384*0b3fd2d3SAndreas Gohr                        if (file_exists($file = $dir . $pathEnd)) {
385*0b3fd2d3SAndreas Gohr                            return $file;
386*0b3fd2d3SAndreas Gohr                        }
387*0b3fd2d3SAndreas Gohr                    }
388*0b3fd2d3SAndreas Gohr                }
389*0b3fd2d3SAndreas Gohr            }
390*0b3fd2d3SAndreas Gohr        }
391*0b3fd2d3SAndreas Gohr
392*0b3fd2d3SAndreas Gohr        // PSR-4 fallback dirs
393*0b3fd2d3SAndreas Gohr        foreach ($this->fallbackDirsPsr4 as $dir) {
394*0b3fd2d3SAndreas Gohr            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395*0b3fd2d3SAndreas Gohr                return $file;
396*0b3fd2d3SAndreas Gohr            }
397*0b3fd2d3SAndreas Gohr        }
398*0b3fd2d3SAndreas Gohr
399*0b3fd2d3SAndreas Gohr        // PSR-0 lookup
400*0b3fd2d3SAndreas Gohr        if (false !== $pos = strrpos($class, '\\')) {
401*0b3fd2d3SAndreas Gohr            // namespaced class name
402*0b3fd2d3SAndreas Gohr            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403*0b3fd2d3SAndreas Gohr                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404*0b3fd2d3SAndreas Gohr        } else {
405*0b3fd2d3SAndreas Gohr            // PEAR-like class name
406*0b3fd2d3SAndreas Gohr            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407*0b3fd2d3SAndreas Gohr        }
408*0b3fd2d3SAndreas Gohr
409*0b3fd2d3SAndreas Gohr        if (isset($this->prefixesPsr0[$first])) {
410*0b3fd2d3SAndreas Gohr            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411*0b3fd2d3SAndreas Gohr                if (0 === strpos($class, $prefix)) {
412*0b3fd2d3SAndreas Gohr                    foreach ($dirs as $dir) {
413*0b3fd2d3SAndreas Gohr                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414*0b3fd2d3SAndreas Gohr                            return $file;
415*0b3fd2d3SAndreas Gohr                        }
416*0b3fd2d3SAndreas Gohr                    }
417*0b3fd2d3SAndreas Gohr                }
418*0b3fd2d3SAndreas Gohr            }
419*0b3fd2d3SAndreas Gohr        }
420*0b3fd2d3SAndreas Gohr
421*0b3fd2d3SAndreas Gohr        // PSR-0 fallback dirs
422*0b3fd2d3SAndreas Gohr        foreach ($this->fallbackDirsPsr0 as $dir) {
423*0b3fd2d3SAndreas Gohr            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424*0b3fd2d3SAndreas Gohr                return $file;
425*0b3fd2d3SAndreas Gohr            }
426*0b3fd2d3SAndreas Gohr        }
427*0b3fd2d3SAndreas Gohr
428*0b3fd2d3SAndreas Gohr        // PSR-0 include paths.
429*0b3fd2d3SAndreas Gohr        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430*0b3fd2d3SAndreas Gohr            return $file;
431*0b3fd2d3SAndreas Gohr        }
432*0b3fd2d3SAndreas Gohr
433*0b3fd2d3SAndreas Gohr        return false;
434*0b3fd2d3SAndreas Gohr    }
435*0b3fd2d3SAndreas Gohr}
436*0b3fd2d3SAndreas Gohr
437*0b3fd2d3SAndreas Gohr/**
438*0b3fd2d3SAndreas Gohr * Scope isolated include.
439*0b3fd2d3SAndreas Gohr *
440*0b3fd2d3SAndreas Gohr * Prevents access to $this/self from included files.
441*0b3fd2d3SAndreas Gohr */
442*0b3fd2d3SAndreas Gohrfunction includeFile($file)
443*0b3fd2d3SAndreas Gohr{
444*0b3fd2d3SAndreas Gohr    include $file;
445*0b3fd2d3SAndreas Gohr}
446