Psr4Autoloader   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 0
dl 0
loc 140
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 4 1
A addNamespace() 0 20 3
A loadClass() 0 28 3
A loadMappedFile() 0 26 4
A requireFile() 0 10 2
1
<?php
2
3
namespace Box\Spout\Autoloader;
4
5
/**
6
 * Class Psr4Autoloader
7
 * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md#class-example
8
 */
9
class Psr4Autoloader
10
{
11
    /**
12
     * An associative array where the key is a namespace prefix and the value
13
     * is an array of base directories for classes in that namespace.
14
     *
15
     * @var array
16
     */
17
    protected $prefixes = [];
18
19
    /**
20
     * Register loader with SPL autoloader stack.
21
     *
22
     * @return void
23
     */
24
    public function register()
25
    {
26
        \spl_autoload_register([$this, 'loadClass']);
27
    }
28
29
    /**
30
     * Adds a base directory for a namespace prefix.
31
     *
32
     * @param string $prefix The namespace prefix.
33
     * @param string $baseDir A base directory for class files in the
34
     * namespace.
35
     * @param bool $prepend If true, prepend the base directory to the stack
36
     * instead of appending it; this causes it to be searched first rather
37
     * than last.
38
     * @return void
39
     */
40
    public function addNamespace($prefix, $baseDir, $prepend = false)
41
    {
42
        // normalize namespace prefix
43
        $prefix = \trim($prefix, '\\') . '\\';
44
45
        // normalize the base directory with a trailing separator
46
        $baseDir = \rtrim($baseDir, DIRECTORY_SEPARATOR) . '/';
47
48
        // initialize the namespace prefix array
49
        if (isset($this->prefixes[$prefix]) === false) {
50
            $this->prefixes[$prefix] = [];
51
        }
52
53
        // retain the base directory for the namespace prefix
54
        if ($prepend) {
55
            \array_unshift($this->prefixes[$prefix], $baseDir);
56
        } else {
57
            \array_push($this->prefixes[$prefix], $baseDir);
58
        }
59
    }
60
61
    /**
62
     * Loads the class file for a given class name.
63
     *
64
     * @param string $class The fully-qualified class name.
65
     * @return mixed The mapped file name on success, or boolean false on
66
     * failure.
67
     */
68
    public function loadClass($class)
69
    {
70
        // the current namespace prefix
71
        $prefix = $class;
72
73
        // work backwards through the namespace names of the fully-qualified
74
        // class name to find a mapped file name
75
        while (($pos = \strrpos($prefix, '\\')) !== false) {
76
            // retain the trailing namespace separator in the prefix
77
            $prefix = \substr($class, 0, $pos + 1);
78
79
            // the rest is the relative class name
80
            $relativeClass = \substr($class, $pos + 1);
81
82
            // try to load a mapped file for the prefix and relative class
83
            $mappedFile = $this->loadMappedFile($prefix, $relativeClass);
84
            if ($mappedFile !== false) {
85
                return $mappedFile;
86
            }
87
88
            // remove the trailing namespace separator for the next iteration
89
            // of strrpos()
90
            $prefix = \rtrim($prefix, '\\');
91
        }
92
93
        // never found a mapped file
94
        return false;
95
    }
96
97
    /**
98
     * Load the mapped file for a namespace prefix and relative class.
99
     *
100
     * @param string $prefix The namespace prefix.
101
     * @param string $relativeClass The relative class name.
102
     * @return mixed Boolean false if no mapped file can be loaded, or the
103
     * name of the mapped file that was loaded.
104
     */
105
    protected function loadMappedFile($prefix, $relativeClass)
106
    {
107
        // are there any base directories for this namespace prefix?
108
        if (isset($this->prefixes[$prefix]) === false) {
109
            return false;
110
        }
111
112
        // look through base directories for this namespace prefix
113
        foreach ($this->prefixes[$prefix] as $baseDir) {
114
            // replace the namespace prefix with the base directory,
115
            // replace namespace separators with directory separators
116
            // in the relative class name, append with .php
117
            $file = $baseDir
118
                  . \str_replace('\\', '/', $relativeClass)
119
                  . '.php';
120
121
            // if the mapped file exists, require it
122
            if ($this->requireFile($file)) {
123
                // yes, we're done
124
                return $file;
125
            }
126
        }
127
128
        // never found it
129
        return false;
130
    }
131
132
    /**
133
     * If a file exists, require it from the file system.
134
     *
135
     * @param string $file The file to require.
136
     * @return bool True if the file exists, false if not.
137
     */
138
    protected function requireFile($file)
139
    {
140
        if (\file_exists($file)) {
141
            require $file;
142
143
            return true;
144
        }
145
146
        return false;
147
    }
148
}
149