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