Autoloader::loadClass()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 27
rs 9.9666
c 0
b 0
f 0
1
<?php
0 ignored issues
show
introduced by
Class file names should be based on the class name with "class-" prepended. Expected class-autoloader.php, but found wp-autoloader.php.
Loading history...
2
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
3
 * @author    WPStore.io <[email protected]>
4
 * @copyright Copyright (c) 2017-2018, WPStore.io
5
 * @license   https://spdx.org/licenses/MIT.html MIT
6
 * @package   WPStore\WPUtils\Autoloader
7
 * @version   1.1.0-dev
8
 */
9
10
/**
11
 * MIT License
12
 *
13
 * Copyright (c) 2017-18 WPStore.io (http://www.wpstore.io)
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to deal
17
 * in the Software without restriction, including without limitation the rights
18
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
 * copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in all
23
 * copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
 * SOFTWARE.
32
 */
33
34
namespace WPUtils;
35
36
/**
37
 * An example of a general-purpose implementation that includes the optional
38
 * functionality of allowing multiple base directories for a single namespace
39
 * prefix.
40
 *
41
 * Given a foo-bar package of classes in the file system at the following
42
 * paths ...
43
 *
44
 *     /path/to/packages/foo-bar/
45
 *         src/
46
 *             Baz.php             # Foo\Bar\Baz
47
 *             Qux/
48
 *                 Quux.php        # Foo\Bar\Qux\Quux
49
 *         tests/
50
 *             BazTest.php         # Foo\Bar\BazTest
51
 *             Qux/
52
 *                 QuuxTest.php    # Foo\Bar\Qux\QuuxTest
53
 *
54
 * ... add the path to the class files for the \Foo\Bar\ namespace prefix
55
 * as follows:
56
 *
57
 *      <?php
58
 *      // instantiate the loader
59
 *      $loader = new \WPUtils\Autoloader;
60
 *
61
 *      // register the autoloader
62
 *      $loader->register();
63
 *
64
 *      // register the base directories for the namespace prefix
65
 *      $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
66
 *      $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');
67
 *
68
 * The following line would cause the autoloader to attempt to load the
69
 * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:
70
 *
71
 *      <?php
72
 *      new \Foo\Bar\Qux\Quux;
73
 *
74
 * The following line would cause the autoloader to attempt to load the
75
 * \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:
76
 *
77
 *      <?php
78
 *      new \Foo\Bar\Qux\QuuxTest;
79
 */
80
81
/**
82
 * Class Autoloader
83
 *
84
 * @package WPStoreUtils
85
 * @See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md
86
 */
87
class Autoloader {
88
89
	/**
90
	 * An associative array where the key is a namespace prefix and the value
91
	 * is an array of base directories for classes in that namespace.
92
	 *
93
	 * @var array
94
	 */
95
	protected $prefixes = array();
96
97
	/**
98
	 * Register loader with SPL autoloader stack.
99
	 *
100
	 * @throws \Exception
0 ignored issues
show
Coding Style introduced by
Comment missing for @throws tag in function comment
Loading history...
101
	 */
102
	public function register() {
103
		spl_autoload_register( array( $this, 'loadClass' ) );
104
	}
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before closing function brace; 0 found
Loading history...
105
106
	/**
107
	 * Adds a base directory for a namespace prefix.
108
	 *
109
	 * @param string $prefix The namespace prefix.
110
	 * @param string $base_dir A base directory for class files in the
111
	 * namespace.
112
	 * @param bool $prepend If true, prepend the base directory to the stack
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
113
	 * instead of appending it; this causes it to be searched first rather
114
	 * than last.
115
	 *
116
	 * @return void
117
	 */
118
	public function addNamespace( $prefix, $base_dir, $prepend = false ) {
0 ignored issues
show
introduced by
Method name "addNamespace" in class Autoloader is not in snake case format, try "add_namespace"
Loading history...
119
		/** normalize namespace prefix */
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
120
		$prefix = trim( $prefix, '\\' ) . '\\';
121
122
		/** normalize the base directory with a trailing separator */
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
123
		$base_dir = rtrim( $base_dir, DIRECTORY_SEPARATOR ) . '/';
124
125
		/** initialize the namespace prefix array */
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
126
		if ( isset( $this->prefixes[ $prefix ] ) === false ) {
127
			$this->prefixes[ $prefix ] = array();
128
		}
129
130
		/** retain the base directory for the namespace prefix */
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
131
		if ( $prepend ) {
132
			array_unshift( $this->prefixes[ $prefix ], $base_dir );
133
		} else {
134
			array_push( $this->prefixes[ $prefix ], $base_dir );
135
		}
136
	}
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before closing function brace; 0 found
Loading history...
137
138
	/**
139
	 * Loads the class file for a given class name.
140
	 *
141
	 * @param string $class The fully-qualified class name.
142
	 *
143
	 * @return mixed The mapped file name on success, or boolean false on
144
	 * failure.
145
	 */
146
	public function loadClass( $class ) {
0 ignored issues
show
introduced by
Method name "loadClass" in class Autoloader is not in snake case format, try "load_class"
Loading history...
147
		// the current namespace prefix
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
148
		$prefix = $class;
149
150
		// work backwards through the namespace names of the fully-qualified
151
		// class name to find a mapped file name
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
152
		while ( false !== $pos = strrpos( $prefix, '\\' ) ) {
0 ignored issues
show
introduced by
Variable assignment found within a condition. Did you mean to do a comparison?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
153
154
			// retain the trailing namespace separator in the prefix
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
155
			$prefix = substr( $class, 0, $pos + 1 );
156
157
			// the rest is the relative class name
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
158
			$relative_class = substr( $class, $pos + 1 );
159
160
			// try to load a mapped file for the prefix and relative class
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
161
			$mapped_file = $this->loadMappedFile( $prefix, $relative_class );
162
			if ( $mapped_file ) {
163
				return $mapped_file;
164
			}
165
166
			// remove the trailing namespace separator for the next iteration
167
			// of strrpos()
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
168
			$prefix = rtrim( $prefix, '\\' );
169
		}
170
171
		// never found a mapped file
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
172
		return false;
173
	}
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before closing function brace; 0 found
Loading history...
174
175
	/**
176
	 * Load the mapped file for a namespace prefix and relative class.
177
	 *
178
	 * @param string $prefix The namespace prefix.
179
	 * @param string $relative_class The relative class name.
180
	 *
181
	 * @return mixed Boolean false if no mapped file can be loaded, or the
182
	 * name of the mapped file that was loaded.
183
	 */
184
	protected function loadMappedFile( $prefix, $relative_class ) {
0 ignored issues
show
introduced by
Method name "loadMappedFile" in class Autoloader is not in snake case format, try "load_mapped_file"
Loading history...
185
		// are there any base directories for this namespace prefix?
186
		if ( isset( $this->prefixes[ $prefix ] ) === false ) {
187
			return false;
188
		}
189
190
		// look through base directories for this namespace prefix
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
191
		foreach ( $this->prefixes[ $prefix ] as $base_dir ) {
192
193
			/**
194
			 * replace the namespace prefix with the base directory,
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
195
			 * replace namespace separators with directory separators
196
			 * in the relative class name, append with .php
197
			 */
198
			$file = $base_dir . str_replace( '\\', '/', $relative_class ) . '.php';
199
200
			// if the mapped file exists, require it
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
201
			if ( $this->requireFile( $file ) ) {
202
				// yes, we're done
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
203
				return $file;
204
			}
205
		}
206
207
		// never found it
0 ignored issues
show
Coding Style introduced by
Inline comments must end in full-stops, exclamation marks, or question marks
Loading history...
208
		return false;
209
	}
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before closing function brace; 0 found
Loading history...
210
211
	/**
212
	 * If a file exists, require it from the file system.
213
	 *
214
	 * @param string $file The file to require.
215
	 *
216
	 * @return bool True if the file exists, false if not.
217
	 */
218
	protected function requireFile( $file ) {
0 ignored issues
show
introduced by
Method name "requireFile" in class Autoloader is not in snake case format, try "require_file"
Loading history...
219
		if ( file_exists( $file ) ) {
220
			require $file;
221
222
			return true;
223
		}
224
225
		return false;
226
	}
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before closing function brace; 0 found
Loading history...
227
228
} // END class
229