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