>  기사  >  개발 도구  >  작곡가 자동 로딩 메커니즘에 대한 자세한 설명

작곡가 자동 로딩 메커니즘에 대한 자세한 설명

藏色散人
藏色散人앞으로
2020-07-06 13:34:353488검색

다음 composer 튜토리얼 칼럼에서는 작곡가 자동 로딩 메커니즘을 더 얕은 것부터 더 깊은 것까지 소개하겠습니다. 필요한 친구들에게 도움이 되길 바랍니다!

작곡가 자동 로딩 메커니즘에 대한 자세한 설명

머리말

작곡가의 자동 로딩 메커니즘에 남은 유일한 메모리는 "spl_auto???"와 "네임스페이스 기반 파일 경로 파생"뿐입니다. . . 아직 불완전합니다. .

온라인에서 자세한 설명을 모으고 싶었지만 내 의견에 맞는 "단순한 것부터 깊은 것까지" 기사를 찾을 수 없었습니다.
그래서 이 메모를 가지고 왔습니다.

다음 지식 포인트가 곧 제공될 예정입니다.
1. spl_autoload_register에 대해 알아보기
2. 작곡가 업데이트 이야기

Text

1. spl_autoload_register에 대해 알아보기


작곡가 자동 로딩 메커니즘에 대한 자세한 설명(게으른 분들은 빨간 부분만 보시면 됩니다)

잘 모르셨나요?

현지어로 번역해 보겠습니다.

새 클래스를 생성하는 경우 먼저 클래스 파일을 요구하거나 포함해야 합니다. 로드되지 않으면 오류가 보고됩니다. 이로 인해 문제가 발생합니다. 이 경우 파일의 헤더는 요구 사항과 포함으로 가득 차 있는데, 이는 분명히 프로그래머의 "게으른" 요구 사항과 일치하지 않습니다.

클래스 파일을 요구하거나 포함하지 않고 정상적으로 새 클래스를 생성하기 위해 자동 로딩 메커니즘이 등장했습니다. spl_autoload_register 함수는 이를 위해 특별히 설계되었습니다.

스크린샷에서 우리는 이 함수에 세 개의 매개변수가 있다는 것을 알 수 있습니다:

Parameters자세한 설명autoload_function여기에 채워진 것은 ***"함수"*의 이름입니다 **, 문자 문자열 또는 배열, 이 기능의 기능은 새로운 경우 오류 보고를 피하기 위해 가능한 한 새로운 파일이 필요한 파일을 요구하거나 포함하는 것입니다. 간단히 말해서 ***파일을 자동으로 로드하는 함수를 캡슐화해야 합니다***throw자동으로 로드되는 함수를 등록할 수 없을 때 예외를 발생시킬지prepend 여부 함수 대기열의 헤드에 함수를 추가하려면 true이면 헤드이고, 그렇지 않으면 테일입니다

来一波代码,印象深刻一些:

//文件 testClass.php ,即将new的类
class TestClass{
    public function __construct() {
        echo '你已经成功new了我了';
    }
}

//文件autoloadDemo.php文件
spl_autoload_register('autoLoad_function', true, true);
function autoLoad_function($class_name){
    echo "所有的require或者include文件工作都交给我吧!\r\n";
    $class_filename = "./{$class_name}.php";
    echo "我来加载{$class_filename}文件\r\n";
    require_once("./{$class_name}.php");
}
$obj_demo = new TestClass();

输出:

所有的require或者include文件工作都交给我吧!
我来加载testClass.php文件
你已经成功new了我了

明白了这个加载的原理,看下文就顺利多了。

2.composer update发生的故事

将自动加载之前,必须要先说一下composer update,这里头承载了自动加载的前提。

composer项目都包含一个composer.json的配置文件。
작곡가 자동 로딩 메커니즘에 대한 자세한 설명
这里头有一个关键的字段"autoload",包含psr-4和files两个字段。

psr-4:说明是基于psr-4规范的类库,都支持自动加载,只要在后面的对象中以**“命名空间:路径”**的方式写入自己的类库信息即可。
files:这就就更直接了,写入路径就自动加载。

按照以上配置每回composer update之后呢,都会更新一个很重要的文件:./vender/composer/autoload_psr4.php。
작곡가 자동 로딩 메커니즘에 대한 자세한 설명

这个文件只做了一件事情:把命名空间和文件路径对应起来,这样后续自动加载就有映射根据了。

3.追踪一下composer的自动加载

composer的故事从唯一的一个require说起:

require '../vendor/autoload.php'

这个脚本执行了一个函数:

ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87::getLoader()

继续跟getloader函数做了什么?

public static function getLoader() {
   if (null !== self::$loader) {
        return self::$loader;
    }

    spl_autoload_register(array('ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87', 'loadClassLoader'), true, true);
    self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    spl_autoload_unregister(array('ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87', 'loadClassLoader'));

    $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
    if ($useStaticLoader) {
        require_once __DIR__ . '/autoload_static.php';

        call_user_func(\Composer\Autoload\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::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);
        }

        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }
    }

    $loader->register(true);

    if ($useStaticLoader) {
        $includeFiles = Composer\Autoload\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::$files;
    } else {
        $includeFiles = require __DIR__ . '/autoload_files.php';
    }
    foreach ($includeFiles as $fileIdentifier => $file) {
        composerRequired9b31141b114fcbee3cf55d0e97b7f87($fileIdentifier, $file);
    }

    return $loader;
}

这个函数主要做了两件事情:
1.将各种存有命名空间和文件映射关系的文件autoload_xxx.php加载了进来,并作了一些处理(比如:setPsr4将相关映射加载了进去,这个留意下,下文会有呼应。)。
2.注册了函数register

继续跟踪register做了什么:

public function register($prepend = false) {
   spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}

原来调用了spl_autoload_register函数,当类没加载的时候使用loadClass来加载类。(这个前文讲的很清楚了,应该很熟了)

继续跟踪loadClass实现:

public function loadClass($class) {
	if ($file = $this->findFile($class)) {
		includeFile($file);
		return true;
	}
}

大概可以看出,是做了文件的include。
继续跟踪下是怎么查找文件的,看findFile函数:

public function findFile($class) {
    // class map lookup
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];
    }
    if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
        return false;
    }
    if (null !== $this->apcuPrefix) {
        $file = apcu_fetch($this->apcuPrefix.$class, $hit);
        if ($hit) {
            return $file;
        }
    }

    $file = $this->findFileWithExtension($class, '.php');

    // Search for Hack files if we are running on HHVM
    if (false === $file && defined('HHVM_VERSION')) {
        $file = $this->findFileWithExtension($class, '.hh');
    }

    if (null !== $this->apcuPrefix) {
        apcu_add($this->apcuPrefix.$class, $file);
    }

    if (false === $file) {
        // Remember that this class does not exist.
        $this->missingClasses[$class] = true;
    }

    return $file;
}

这个函数做了一件事:就是寻找类从上文的autoload_xxx.php初始化的数据中来寻找映射的文件路径。
其中这个函数findFileWithExtension,适用于寻找psr-4规范的文件的映射信息的。

继续跟踪findFileWithExtension:

private function findFileWithExtension($class, $ext) {
    // PSR-4 lookup
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

    $first = $class[0];
    if (isset($this->prefixLengthsPsr4[$first])) {
        $subPath = $class;
        while (false !== $lastPos = strrpos($subPath, '\\')) {
            $subPath = substr($subPath, 0, $lastPos);
            $search = $subPath.'\\';
            if (isset($this->prefixDirsPsr4[$search])) {
                $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                foreach ($this->prefixDirsPsr4[$search] as $dir) {
                    if (file_exists($file = $dir . $pathEnd)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-4 fallback dirs
    foreach ($this->fallbackDirsPsr4 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
            return $file;
        }
    }

    // PSR-0 lookup
    if (false !== $pos = strrpos($class, '\\')) {
        // namespaced class name
        $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
    } else {
        // PEAR-like class name
        $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
    }

    if (isset($this->prefixesPsr0[$first])) {
        foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
            if (0 === strpos($class, $prefix)) {
                foreach ($dirs as $dir) {
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-0 fallback dirs
    foreach ($this->fallbackDirsPsr0 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
            return $file;
        }
    }

    // PSR-0 include paths.
    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
        return $file;
    }

    return false;
}

这个函数做了件事:将命名空间\类这样的类名,转换成目录名/类名.php这样的路径,再从前文setPsr4设置的映射信息中寻找映射信息,然后完成返回路径。

至此composer的自动加载机制结束。

위 내용은 작곡가 자동 로딩 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제