(2) Autoload

Time:2021-7-14

Thinkphp6 & laravel7 & swoft both use composer to load class libraries.

To access the entry file of the framework, the first thing for the framework is to configure automatic loading, which is the basic work of calling and instantiating the following classes.

Why do I need to load automatically?

When using undefined classes and interfaces, automatically search and load class files. Make a last ditch struggle before PHP throws an error.

The implementation principle of the whole composer is as follows: first, each class or mapping class using different PSR specifications is stored in some form, and then when the class cannot be found, the path of the class is found by matching with the stored data, and then it is loaded.

Automatic loading saves manual operation to require / include, improves the convenience, but brings some performance loss.

Composer third-party class library is to achieve this function, why do we all use this class library. Let’s explore the class library code and how to find class files.

 

As can be seen from the activity diagram above, there are actually four kinds of standard files to load for composer.

They are: psr0, psr4, class mapping and common function file.

Now through the analysis of the code, how to realize the composer.

Autoload.php file, initializing classloader class, is also the protagonist of the whole loading process.

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit35e14f048fbf9badf052d7e5a5050e37::getLoader();
= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            //Getinitializer returns the closure class. This class is an implementation of anonymous functions. So it can be called back.
            call_user_func(\Composer\Autoload\ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::getInitializer($loader));
        } else {
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            //Load mapping: class name - > Path
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->register(true);

        //Automatically load the file, loading the public function
        if ($useStaticLoader) {
            $includeFiles = Composer\Autoload\ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$files;
        } else {
            $includeFiles = require __DIR__ . '/autoload_files.php';
        }
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire35e14f048fbf9badf052d7e5a5050e37($fileIdentifier, $file);
        }

        return $loader;
    }
}

//Load global functions. You can use global variables to see which global file has been loaded.
function composerRequire35e14f048fbf9badf052d7e5a5050e37($fileIdentifier, $file)
{
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        require $file;

        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
    }
}

A technique is used here. If the member property of the object class is private and the set method has been implemented, now you need to implement the same function and directly copy it to the private member property. If the common method is to change the private property to public, or modify the set method, or add a new method. However, the attribute of the system class closure is used here, and the private attribute of the target object can be used through the bind method.

autoload_static.php

public static function getInitializer(ClassLoader $loader)
    {
        //Copy a closure to bind the classloader scope. Private methods can be manipulated. Assign value to array directly to reduce the number of operations.
        //Initialize the classes that need to be loaded
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixDirsPsr4;
            $loader->fallbackDirsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$fallbackDirsPsr4;
            $loader->prefixesPsr0 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixesPsr0;
            $loader->classMap = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$classMap;

        }, null, ClassLoader::class);
    }

Psr0, psr4, you can first check the specific specifications:

https://www.php-fig.org/psr/psr-4/

https://www.php-fig.org/psr/psr-0/

Generally speaking, the path of psr0 is to add a new path name in front of the original namespace, and the class name encounters an underline, Also need to convert to directory separator; Psr4 replaces the namespace prefix with a path.

In order to quickly screen the matching, composer first filters the initials and then matches the specific namespace.

 

 

 

 

Finally, SPL is used_ autoload_ Register system function to configure user-defined load function, greatly improving the convenience.