Automatic loading of tp5 source code parsing


It is simple and convenient. Automatic loading allows code to use a class without introducing it manually. It is based on the use of namespaces


TP version ='5.1.39 lts' (5.1 is OK)
Familiar with PHP built-in functions

code implementation

The first step of the entry file is to load the basic file base.php, load the Loader.php class, and register to automatically load Loader::register();
The main function of register() is to register for automatic loading, and then set the property (self::$prefixDirsPsr4...)
Map namespace (app, think...) to file path

    // Register auto loading mechanism
    public static function register($autoload = '')
        // Use autoload method under this class when auto load parameter of registration system is empty
        spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);

        // Get app root $rootPath =\
        // The value in the following note defaults to the value generated by the first time you use this method, that is, the action of registering to automatically load Loader::register(); in base.php
        $rootPath = self::getRootPath();

        //self::$composerPath = \vendor\composer\
        self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;

        // Composer auto load support
        if (is_dir(self::$composerPath)) {
            if (is_file(self::$composerPath . 'autoload_static.php')) {
                require self::$composerPath . 'autoload_static.php';

                //Returns an array of the names of defined classes
                $declaredClass = get_declared_classes();

                //$composerClass = Composer\Autoload\ComposerStaticInitb22aa0543af0539791954cd9546b8e78
                //That is to say, the classes in the autoload_static.php file introduced earlier may be different for everyone
                $composerClass = array_pop($declaredClass);
//        var_dump($composerClass);die;

                foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {
                    if (property_exists($composerClass, $attr)) {
                        self::${$attr} = $composerClass::${$attr};
                //This class now has several properties' prefixLengthsPsr4 '... The content is consistent with that in autoload_static.php
            } else {

        // Register namespace definition
//        Here are two entries in the self::$prefixDirsPsr4 array
//        self::$prefixDirsPsr4 = [
//                  'think\composer\' => [ __DIR__ . '/..' . '/topthink/think-installer/src']
//                  'app\' =>[__DIR__ . '/../..' . '/application',]
//                  'think\' => ['$rootPath.thinkphp\library\think']
//                  'traits\' => [$rootPath.'thinkphp\library\traits']
//              ]
//        This array points the namespace to the corresponding file path
            'think'  => __DIR__,
            'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',

        // Load class library mapping file
        if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
            self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));

        // The autoload extend directory is similar to the previous self::addNamespace() method
        self::addAutoLoadDir($rootPath . 'extend');

autoload method is to find the file corresponding to $class, and finally import the file

// Automatic loading
    public static function autoload($class)
//        $class ='think\Error '; execute Error::register() in base.php; cannot find the inside of think\Error, pass the class name to reference
        if (isset(self::$classAlias[$class])) {
            return class_alias(self::$classAlias[$class], $class);

        //Find the file corresponding to $class and assign it to file. Finally, import file
        if ($file = self::findFile($class)) {

            // Win environment is case sensitive
            if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
                return false;

            return true;

Then look at the findFile method,

     * Find file
     * @access private
     * @param  string $class
     * @return string|false
    private static function findFile($class)
        if (!empty(self::$classMap[$class])) {
            // Class library mapping
            return self::$classMap[$class];

        // Find PSR-4
        //$logicalPathPsr4 = "think\Error.php"
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';

        //The following respectively corresponds to several different scenarios, using several attributes set in the register() method to splice paths from different attributes,
        $first = $class[0]; //first = t
        if (isset(self::$prefixLengthsPsr4[$first])) {
            foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
                if (0 === strpos($class, $prefix)) {
                    foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
                        if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
                            return $file;
        //The following is omitted
        // Find PSR-4 fallback dirs      
        // Find PSR-0    
        // Find PSR-0 fallback dirs

        return self::$classMap[$class] = false;


Register register to load automatically and then set properties
autoLoad calls findFile, and finally introduces the file
findFile finds the file corresponding to $class according to the property set by register

To see these codes, you should often use breakpoints to view variable values~~~~

Tags: PHP

Posted on Fri, 29 Nov 2019 06:26:24 -0800 by 7pm