FIG-PHPPSR specification series 4-automatic loading

Source: Internet
Author: User
Tags autoloader spl
FIG-PHPPSR specification series 4-automatic loading 1. PSR-4 specification: automatic loading

Although it was pointed out in [PSR-4-Meta] that the PSR-4 was a supplement to the PSR-0 specification rather than a replacement, but it had been written in [PSR-0] that PSR-0 was deprecated on, and in the [PSR-4-Meta] Detailed description of the lack of PSR-0, can not meet the automatic loading for package.

The PSR-4 specification can meet the automatic loading for package, it standardizes how classes are automatically loaded from the file path, while standardizes the location of the automatically loaded file.

1.1 Overview

This section describes how to automatically load classes from a file path. Can interoperate with PSR-0 specifications, can be used together. This section also describes where the automatically loaded files should be stored.

1.2 specification

1.2.1 The term "class" refers to classes, interfaces, traits, and other similar structures.

1.2.2 A fully qualified class name is in the following format:

\ (\ )*\

(1) a fully compliant class name MUST (MUST) have a top-level namespace name, which is commonly referred to as "vendor namespace ".

(2) a fully compliant class name can (MAY) have one or more second-level namespaces (sub-namespace names ).

(3) fully compliant class names MUST end with class names (MUST.

(4) in any part of the fully compliant class name, the underline has no special meaning.

(5) in fully compliant class names, (MAY) can be any combination of uppercase and lowercase letters.

(6) all class names MUST be referenced (MUST) in case sensitive mode.

1.2.3 when the file corresponding to the fully compliant class name is loaded...

(1) a fully compliant class name does not contain the preceding namespace separator. it is a namespace prefix consisting of a top-level namespace and one or more second-level namespace names, corresponds to at least one "base Directory ".

(2) the second-level namespace name after the namespace prefix corresponds to a sub-directory in the "base Directory". here, the namespace separator represents the directory separator. The subdirectory name MUST match the second-level namespace name (MUST.

(3) the class name after the class name corresponds to the file name suffixed with. php. the file name MUST be (MUST) matched with the class name.

(4) the automatic loading implementation must not throw an exception (must not). it must not (must not) trigger any level of errors and should not return values (shocould NOT.

1.3. example

The following table shows a fully compliant class name, namespace prefix, and the file path corresponding to the base directory.

Full compliance class name Namespace prefix Base Directory Final file path
\ Acme \ Log \ Writer \ File_Writer Acme \ Log \ Writer ./Acme-log-writer/lib/ ./Acme-log-writer/lib/File_Writer.php
\ Aura \ Web \ Response \ Status Aura \ Web /Path/to/aura-web/src/ /Path/to/aura-web/src/Response/Status. php
\ Symfony \ Core \ Request Symfony \ Core ./Vendor/Symfony/Core/ ./Vendor/Symfony/Core/Request. php
\ Zend \ Acl Zend /Usr/includes/Zend/ /Usr/includes/Zend/Acl. php

Note: In the first behavior example, the fully compliant class name is "\ Acme \ Log \ Writer \ File_Writer", removing the namespace separator '\', the namespace prefix is "Acme \ Log \ Writer" and the class name is "File_Writer ". The base directory corresponding to the namespace prefix is ". /acme-log-writer/lib/", so the final file name to be loaded is: base Directory + class name + ". php ", that is ". /acme-log-writer/lib/File_Writer.php"


See the following sample code for the implementation of the auto-loader following this specification. These implementation samples must not be considered as content of this specification, and they MAY change at any time.

2. Sample code

The following code shows the class definitions that follow the PSR-4,

Closure example:

   

The following class processes multiple namespaces:

  Register (); ** // register the base directories for the namespace prefix * // register multiple base directories with 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 wocould cause the autoloader to attempt to load the * \ Foo \ Bar \ Qux \ Quux class from/path/to/packages/foo-bar/src/Qux/ quux. php: * The following code uses/path/ The/packages/foo-bar/src/Qux/Quux. php file loads the \ Foo \ Bar \ Qux \ Quux class. **
  Prefixes [$ prefix]) ==== false) {$ this-> prefixes [$ prefix] = array ();} // retain the base directory for the namespace prefix // bind the base directory corresponding to the namespace prefix if ($ 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. * load class files based on class names. ** @ 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 name // traverse the namespace name in the fully qualified class name from the end, to find the ing file name while (false! ==$ Pos = strrpos ($ prefix ,'\\')) {// retain the trailing namespace separator in the prefix // reserve the delimiter at the end of the namespace prefix $ prefix = substr ($ class, 0, $ pos + 1 ); // the rest is the relative class name // the remaining is the relative class name $ relative_class = substr ($ class, $ pos + 1 ); // try to load a mapped file for the prefix and relative class // use the namespace prefix and relative class name to load the ing file $ mapped_file = $ this-> loadMappedFile ($ prefix, $ relative_class); if ($ Mapped_file) {return $ mapped_file;} // remove the trailing namespace separator for the next iteration // of strrpos () // delete the delimiter at the end of the namespace prefix, used for the next strrpos () iteration $ prefix = rtrim ($ prefix, '\');} // never found a mapped file // The return ing file is not found, return false ;} /*** Load the mapped file for a namespace prefix and relative class. * load The ing file based on The namespace prefix and relative class ** @ param string $ prefix The namespace prefix. * @ param s Tring $ 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? // Is there a base directory in the namespace prefix? If (isset ($ this-> prefixes [$ prefix]) ===false) {return false ;} // look through base directories for this namespace prefix // traverse the base Directory of the namespace prefix foreach ($ 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 // replace the namespace prefix with the base directory, // replace the namespace separator '\' with the directory separator '/' in the relative class name, // and append it later. php: the absolute path of $ file = $ base_dir. str_replace ('\', '/', $ relative_class ). '. php '; // if the mapped file exists, require it // if the ing file exists, require the file if ($ this-> requireFile ($ file )) {// yes, we're done return $ file;} // never found it return 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 ;}}
3. unit test

The unit test code is as follows:

  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);    }}
4. PSR-4 application

The PHP package management system Composer already supports PSR-4, and also allows different auto-loading mechanisms to be defined in composer. json.

Composer use PSR-0 style

vendor/    vendor_name/        package_name/            src/                Vendor_Name/                    Package_Name/                        ClassName.php       # Vendor_Name\Package_Name\ClassName            tests/                Vendor_Name/                    Package_Name/                        ClassNameTest.php   # Vendor_Name\Package_Name\ClassName

Composer use PSR-4 style

vendor/    vendor_name/        package_name/            src/                ClassName.php       # Vendor_Name\Package_Name\ClassName            tests/                ClassNameTest.php   # Vendor_Name\Package_Name\ClassNameTest

Comparing the above two structures, we can see that the PSR-4 brings a more concise file structure.

5. References

[PHP-FIG] php-fig, http://www.php-fig.org/

[PSR-0] Autoloading Standard, http://www.php-fig.org/psr/psr-0/

[PSR-4] Autoloader, http://www.php-fig.org/psr/psr-4/

[PSR-4-Meta] PSR-4 Meta Document, http://www.php-fig.org/psr/psr-4/meta/

[PSR-4-Example] Example Implementations of PSR-4, http://www.php-fig.org/psr/psr-4/examples/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.