Completed
Push — b0.27.0 ( c529b3...34cc26 )
by Sebastian
05:07
created

Autoloader   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 10
eloc 24
c 3
b 0
f 1
dl 0
loc 113
ccs 28
cts 28
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A unregister() 0 3 1
A register() 0 3 1
A addNamespaces() 0 13 2
A loadMappedFile() 0 21 3
A loadClass() 0 20 3
1
<?php
2
3
/**
4
 * Linna Framework.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna;
13
14
/**
15
 * PSR-4 Autoloader.
16
 *
17
 * An example of a general-purpose implementation that includes the optional
18
 * functionality of allowing multiple base directories for a single namespace
19
 * prefix.
20
 *
21
 * Given a foo-bar package of classes in the file system at the following
22
 * paths ...
23
 *
24
 *     /path/to/packages/foo-bar/
25
 *         src/
26
 *             Baz.php             # Foo\Bar\Baz
27
 *             Qux/
28
 *                 Quux.php        # Foo\Bar\Qux\Quux
29
 *         tests/
30
 *             BazTest.php         # Foo\Bar\BazTest
31
 *             Qux/
32
 *                 QuuxTest.php    # Foo\Bar\Qux\QuuxTest
33
 *
34
 * ... add the path to the class files for the \Foo\Bar\ namespace prefix
35
 * as follows:
36
 *
37
 *      <?php
38
 *      // instantiate the loader
39
 *      $loader = new \Example\Psr4AutoloaderClass;
40
 *
41
 *      // register the autoloader
42
 *      $loader->register();
43
 *
44
 *      $nm = [
45
 *          ['Foo\Bar', '/path/to/packages/foo-bar/src'],
46
 *          ['Foo\Bar', '/path/to/packages/foo-bar/tests']
47
 *      ];
48
 *
49
 *      // register the base directories for the namespace prefix
50
 *      $loader->addNamespaces($nm);
51
 *
52
 *
53
 * The following line would cause the autoloader to attempt to load the
54
 * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:
55
 *
56
 *      <?php
57
 *      new \Foo\Bar\Qux\Quux;
58
 *
59
 * The following line would cause the autoloader to attempt to load the
60
 * \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:
61
 *
62
 *      <?php
63
 *      new \Foo\Bar\Qux\QuuxTest;
64
 */
65
class Autoloader
66
{
67
    /**
68
     * An associative array where the key is a namespace prefix and the value
69
     * is an array of base directories for classes in that namespace.
70
     *
71
     * @var array
72
     */
73
    protected array $prefixes = [];
74
75
    /**
76
     * Register loader with SPL autoloader stack.
77
     *
78
     * @return bool
79
     */
80 6
    public function register(): bool
81
    {
82 6
        return \spl_autoload_register([$this, 'loadClass']);
83
    }
84
85
    /**
86
     * Unregister loader with SPL autoloader stack.
87
     *
88
     * @return bool
89
     */
90 6
    public function unregister(): bool
91
    {
92 6
        return \spl_autoload_unregister([$this, 'loadClass']);
93
    }
94
95
    /**
96
     * Adds a base directory for a namespace prefix, accept an array of namespaces
97
     * Utilize this for prevente multiple addNamespace() calls.
98
     *
99
     * @param array $namespaces The namespace prefix array.
100
     *
101
     * @return void
102
     */
103 6
    public function addNamespaces(array $namespaces): void
104
    {
105
        //loop for add single namespace
106 6
        foreach ($namespaces as $namespace) {
107
108
            // normalize namespace prefix
109 6
            $prefix = \trim($namespace[0], '\\');
110
111
            // normalize the base directory with a trailing separator
112 6
            $baseDir = \rtrim($namespace[1], DIRECTORY_SEPARATOR).'/';
113
114
            //add namespace
115 6
            $this->prefixes[$prefix] = $baseDir;
116
        }
117 6
    }
118
119
    /**
120
     * Loads the class file for a given class name.
121
     *
122
     * @param string $class The fully-qualified class name.
123
     *
124
     * @return bool True on success, false on failure.
125
     */
126 6
    public function loadClass(string $class): bool
127
    {
128 6
        $arrayClass = \explode('\\', $class);
129
130 6
        $arrayPrefix = [];
131
132 6
        while (\count($arrayClass)) {
133 6
            $arrayPrefix[] = \array_shift($arrayClass);
134
135 6
            $prefix = \implode('\\', $arrayPrefix);
136 6
            $relativeClass = \implode('\\', $arrayClass);
137
138
            // try to load a mapped file for the prefix and relative class
139 6
            if ($this->loadMappedFile($prefix, $relativeClass)) {
140 2
                return true;
141
            }
142
        }
143
144
        // never found a mapped file
145 4
        return false;
146
    }
147
148
    /**
149
     * Load the mapped file for a namespace prefix and relative class.
150
     *
151
     * @param string $prefix        The namespace prefix.
152
     * @param string $relativeClass The relative class name.
153
     *
154
     * @return bool Boolean false there are any base directories for namespace prefix or file,
155
     *              true on success.
156
     */
157 6
    private function loadMappedFile(string $prefix, string $relativeClass): bool
158
    {
159
        // are there any base directories for this namespace prefix?
160 6
        if (empty($this->prefixes[$prefix])) {
161 6
            return false;
162
        }
163
164
        // replace namespace separators with directory separators
165
        // in the relative class name, append with .php
166 3
        $file = $this->prefixes[$prefix].\str_replace('\\', '/', $relativeClass).'.php';
167
168
        // if the mapped file exists, require it
169 3
        if (\file_exists($file)) {
170 2
            require $file;
171
172
            // yes, we're done
173 2
            return true;
174
        }
175
176
        //Unable to find class in file.
177 1
        return false;
178
    }
179
}
180