fig-php PSR Specification Series 4-Automatic loading

Source: Internet
Author: User
Tags autoloader spl rtrim
1. PSR-4 Specification: Automatic loading

Although it is noted in [Psr-4-meta] that PSR-4 is a supplement to the PSR-0 specification rather than a replacement, it has been written in [PSR-0] that PSR-0 was abandoned in 2014.10.21 and that the Psr-4-meta was detailed in [PSR-0], Automatic loading for package is not available.

The PSR-4 specification is capable of automatic loading for package, which regulates how classes are automatically loaded from file paths, and also regulates the location of automatically loaded files.

1.1 Overview

This PSR specification describes the automatic loading of classes from file paths. Can interoperate with the PSR-0 specification and can be used together. This PSR also describes where the automatically loaded files should be placed.

1.2 Specifications

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

1.2. The 21 fully compliant class names (A fully qualified class name) are in the following format:

\ (\ )*\

(1) A fully compliant class name must (must) have a top-level namespace name, which is commonly referred to as the "Vendor namespace."

(2) A fully compliant class name can (May) have one or more level two namespace names (sub-namespace names).

(3) A fully compliant class name must (must) end with the class name.

(4) In any part of a fully compliant class name, the underscore does not have a special meaning.

(5) In a fully compliant class name, you can (may) be any combination of uppercase and lowercase letters.

(6) All class names must (must) be referenced in a case-sensitive manner.

1.2.3 when loading a file corresponding to a fully compliant class name ...

(1) In a fully compliant class name, does not contain the preceding namespace delimiter, a namespace prefix consisting of one top-level namespace and one or more level two namespace names, corresponding to at least one "base directory".

(2) The two-level namespace name after the namespace prefix corresponds to a subdirectory in the base directory, where the namespace delimiter represents the directory delimiter. The subdirectory name must (must) match to a level two namespace name.

(3) The following class name corresponds to a file name with a suffix of. php, which must match (must) to the following class name.

(4) Automatic loading implementation must not (must not) throw an exception, must not (must not) raise any level of error, and should not (should not) return a value.

1.3. For example

The following table shows the file paths that correspond to a fully compliant class name, namespace prefix, and base directory.

Full Compliance class name Namespace prefixes Base directory The 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: As explained in the first example, the fully compliant class name is "\acme\log\writer\file_writer" and the preceding namespace delimiter ' \ ' is removed, then the namespace prefix is "Acme\log\writer" and the class name is "File_writer". This namespace prefix corresponds to "./acme-log-writer/lib/" for the base directory, so the final loaded file name is: Base directory + class name + ". php", i.e. "./acme-log-writer/lib/file_ Writer.php "


Examples of implementations of the autoloader following this specification can be found in the code sample below. These implementation samples must not (must not) be considered as content of this specification and may change at any time.

2. Code examples

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

Closures (Closure) Examples:

   

The following class handles multiple namespaces:

  Register (); * *//Register the base directories for the namespace prefix *//Register multiple base directories for namespace prefixes * $loader->ad Dnamespace (' 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: * The following code will load the \foo\bar\qux\quux class with the/path/to/packages/foo-bar/src/qux/quux.php file.       *  *
  prefixes[$prefix]) = = = False) {$this->prefixes[$prefix] = array ();            }//retain the base directory for the namespace prefix//binding namespace prefix corresponding to the base catalog 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 the class file according to the 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 name From the back, iterate through the namespace name in the fully qualified class name to find the mapped file name while (false!== $pos = Strrpos ($prefix, ' \ \ ')) {//retain the TR     Ailing namespace separator in the prefix       Leave the trailing delimiter in the namespace prefix $prefix = substr ($class, 0, $pos + 1);            The rest is the relative class name//The remaining is relative to the category names $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 mapping files $map            Ped_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 trailing end of the namespace prefix for use with the next Strrpos () Iteration $prefix = RTrim ($prefix, ' \ \ ');    }//never found a mapped file//No mapping files found return false;     }/** * Load the mapped file for a namespace prefix and relative class.     * Load the mapping file according to the 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 is loaded. */protected function Loadmappedfile ($prefix, $relative _class) {//Is there any base directories for this n        Amespace prefix?        Does the namespace prefix have a base directory?        if (Isset ($this->prefixes[$prefix]) = = = False) {return false; }//Look through the base directories for this namespace prefix//traverse the namespace prefix of the base directory foreach ($this->pr efixes[$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//using B The ASE directory overrides the namespace prefix,//replaces the namespace delimiter ' \ ' with the directory delimiter '/' in the relative class name, and//and appends it later. The absolute path of PHP composition $file = $base _dir. Str_replace (' \ \ ', '/', $relative _class).            '. php ';       If the mapped file exists, require it     If the mapping file exists, then 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 Testing

The following is the corresponding unit test code:

  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/DOOMC            Lassname.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); The Public Function Testdeepfile () {$actual = $this->loader->loadclass (' Foo\bar\baz\dib\zim\gir\classnam        E '); $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

PHP's package management system composer already supports PSR-4, while also allowing different prefix to be defined in Composer.json.

Composer using 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 using 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 these two structures, it is obvious that PSR-4 brings 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/

  • Related Article

    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.