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