다음 예는 PSR-4에 호환하는 코드입니다.
역자주: 사실상 오토로더는 컴포저로 대동단결 되었기 때문에 직접 구현하시기 보다는 컴포저를 사용하시는 것을 추천합니다
<?php/*** An example of a project-specific implementation.** After registering this autoload function with SPL, the following line* would cause the function to attempt to load the \Foo\Bar\Baz\Qux class* from /path/to/project/src/Baz/Qux.php:** new \Foo\Bar\Baz\Qux;** @param string $class The fully-qualified class name.* @return void*/spl_autoload_register(function ($class) {// project-specific namespace prefix$prefix = 'Foo\\Bar\\';// base directory for the namespace prefix$base_dir = __DIR__ . '/src/';// does the class use the namespace prefix?$len = strlen($prefix);if (strncmp($prefix, $class, $len) !== 0) {// no, move to the next registered autoloaderreturn;}// get the relative class name$relative_class = substr($class, $len);// replace the namespace prefix with the base directory, replace namespace// separators with directory separators in the relative class name, append// with .php$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';// if the file exists, require itif (file_exists($file)) {require $file;}});
다음은 네임스페이스를 활용하여 여러 클래스를 처리하기위한 클래스 구현의 예제입니다.
<?phpnamespace Example;/*** An example of a general-purpose implementation that includes the optional* functionality of allowing multiple base directories for a single namespace* prefix.** Given a foo-bar package of classes in the file system at the following* paths ...** /path/to/packages/foo-bar/* src/* Baz.php # Foo\Bar\Baz* Qux/* Quux.php # Foo\Bar\Qux\Quux* tests/* BazTest.php # Foo\Bar\BazTest* Qux/* QuuxTest.php # Foo\Bar\Qux\QuuxTest** ... add the path to the class files for the \Foo\Bar\ namespace prefix* as follows:** <?php* // instantiate the loader* $loader = new \Example\Psr4AutoloaderClass;** // register the autoloader* $loader->register();** // register the base directories for the namespace prefix* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');* $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');** The following line would cause the autoloader to attempt to load the* \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:** <?php* new \Foo\Bar\Qux\Quux;** The following line would cause the autoloader to attempt to load the* \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:** <?php* new \Foo\Bar\Qux\QuuxTest;*/class Psr4AutoloaderClass{/*** An associative array where the key is a namespace prefix and the value* is an array of base directories for classes in that namespace.** @var array*/protected $prefixes = array();/*** Register loader with SPL autoloader stack.** @return void*/public function register(){spl_autoload_register(array($this, 'loadClass'));}/*** Adds a base directory for a namespace prefix.** @param string $prefix The namespace prefix.* @param string $base_dir A base directory for class files in the* namespace.* @param bool $prepend If true, prepend the base directory to the stack* instead of appending it; this causes it to be searched first rather* than last.* @return void*/public function addNamespace($prefix, $base_dir, $prepend = false){// normalize namespace prefix$prefix = trim($prefix, '\\') . '\\';// normalize the base directory with a trailing separator$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';// initialize the namespace prefix arrayif (isset($this->prefixes[$prefix]) === false) {$this->prefixes[$prefix] = array();}// retain the base directory for the namespace prefixif ($prepend) {array_unshift($this->prefixes[$prefix], $base_dir);} else {array_push($this->prefixes[$prefix], $base_dir);}}/*** Loads the class file for a given class name.** @param string $class The fully-qualified class name.* @return mixed The mapped file name on success, or boolean false on* failure.*/public function loadClass($class){// the current namespace prefix$prefix = $class;// work backwards through the namespace names of the fully-qualified// class name to find a mapped file namewhile (false !== $pos = strrpos($prefix, '\\')) {// retain the trailing namespace separator in the prefix$prefix = substr($class, 0, $pos + 1);// the rest is the relative class name$relative_class = substr($class, $pos + 1);// try to load a mapped file for the prefix and relative class$mapped_file = $this->loadMappedFile($prefix, $relative_class);if ($mapped_file) {return $mapped_file;}// remove the trailing namespace separator for the next iteration// of strrpos()$prefix = rtrim($prefix, '\\');}// never found a mapped filereturn false;}/*** Load the mapped file for a namespace prefix and relative class.** @param string $prefix The namespace prefix.* @param string $relative_class The relative class name.* @return mixed Boolean false if no mapped file can be loaded, or the* name of the mapped file that was loaded.*/protected function loadMappedFile($prefix, $relative_class){// are there any base directories for this namespace prefix?if (isset($this->prefixes[$prefix]) === false) {return false;}// look through base directories for this namespace prefixforeach ($this->prefixes[$prefix] as $base_dir) {// replace the namespace prefix with the base directory,// replace namespace separators with directory separators// in the relative class name, append with .php$file = $base_dir. str_replace('\\', '/', $relative_class). '.php';// if the mapped file exists, require itif ($this->requireFile($file)) {// yes, we're donereturn $file;}}// never found itreturn false;}/*** If a file exists, require it from the file system.** @param string $file The file to require.* @return bool True if the file exists, false if not.*/protected function requireFile($file){if (file_exists($file)) {require $file;return true;}return false;}}
다음 예제는 위의 클래스 로더를 단위 테스트하는 방법의 한 가지입니다.
<?phpnamespace Example\Tests;class MockPsr4AutoloaderClass extends Psr4AutoloaderClass{protected $files = array();public function setFiles(array $files){$this->files = $files;}protected function requireFile($file){return in_array($file, $this->files);}}class Psr4AutoloaderClassTest extends \PHPUnit_Framework_TestCase{protected $loader;protected function setUp(){$this->loader = new MockPsr4AutoloaderClass;$this->loader->setFiles(array('/vendor/foo.bar/src/ClassName.php','/vendor/foo.bar/src/DoomClassName.php','/vendor/foo.bar/tests/ClassNameTest.php','/vendor/foo.bardoom/src/ClassName.php','/vendor/foo.bar.baz.dib/src/ClassName.php','/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php',));$this->loader->addNamespace('Foo\Bar','/vendor/foo.bar/src');$this->loader->addNamespace('Foo\Bar','/vendor/foo.bar/tests');$this->loader->addNamespace('Foo\BarDoom','/vendor/foo.bardoom/src');$this->loader->addNamespace('Foo\Bar\Baz\Dib','/vendor/foo.bar.baz.dib/src');$this->loader->addNamespace('Foo\Bar\Baz\Dib\Zim\Gir','/vendor/foo.bar.baz.dib.zim.gir/src');}public function testExistingFile(){$actual = $this->loader->loadClass('Foo\Bar\ClassName');$expect = '/vendor/foo.bar/src/ClassName.php';$this->assertSame($expect, $actual);$actual = $this->loader->loadClass('Foo\Bar\ClassNameTest');$expect = '/vendor/foo.bar/tests/ClassNameTest.php';$this->assertSame($expect, $actual);}public function testMissingFile(){$actual = $this->loader->loadClass('No_Vendor\No_Package\NoClass');$this->assertFalse($actual);}public function testDeepFile(){$actual = $this->loader->loadClass('Foo\Bar\Baz\Dib\Zim\Gir\ClassName');$expect = '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php';$this->assertSame($expect, $actual);}public function testConfusion(){$actual = $this->loader->loadClass('Foo\Bar\DoomClassName');$expect = '/vendor/foo.bar/src/DoomClassName.php';$this->assertSame($expect, $actual);$actual = $this->loader->loadClass('Foo\BarDoom\ClassName');$expect = '/vendor/foo.bardoom/src/ClassName.php';$this->assertSame($expect, $actual);}}