: This article mainly introduces the PSR-4 instance, for PHP tutorials interested in students can refer. Here is an example of implementing the PSR-4 specification:
Closure Example
Class Example
The following is an example of a class for processing multiple namespaces.
Register (); ** // register the base Directory 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 code will trigger autoloader to try from */path/to/packages/foo-bar/src/Qux/Quux. php loading * \ Foo \ Bar \ Qux \ Quux class :** 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. */publicfunctionloadClass ($ 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 traili Ng namespace separator for the next iteration // of strrpos () $ prefix = rtrim ($ prefix, '\');} // never found a mapped filereturnfalse ;} /*** 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 mapp Ed file that was loaded. */protectedfunctionloadMappedFile ($ prefix, $ relative_class) {// are there any base directories for this namespace prefix? If (isset ($ this-> prefixes [$ prefix]) ===false) {returnfalse ;} // 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. 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 itreturnfalse;}/*** 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. */protectedfunctionrequireFile ($ file) {if (file_exists ($ file) {require $ file; returntrue ;} returnfalse ;}}
Unit Tests
The following example is one way of unit testing the above class loader:
files = $files; } protectedfunctionrequireFile($file) {return in_array($file, $this->files); }}classPsr4AutoloaderClassTestextends \PHPUnit_Framework_TestCase{protected$loader; protectedfunctionsetUp() {$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' ); } publicfunctiontestExistingFile() {$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); } publicfunctiontestMissingFile() {$actual = $this->loader->loadClass('No_Vendor\No_Package\NoClass'); $this->assertFalse($actual); } publicfunctiontestDeepFile() {$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); } publicfunctiontestConfusion() {$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); }}