composer的autoloader源码追踪

本文详细解析了 Composer 安装依赖后如何生成自动加载文件的过程,包括命名空间、PSR-4 目录及类映射等配置的生成。

首先理顺一下文件加载先后顺序


上面这几个文件都是在执行composer install 后生成的,那么问题来了,这些文件是怎么生成的?

追踪源码,可以发现生成逻辑如下:

首先composer/installer.php文件中执行到run()函数中,下载完所有依赖包,生成composer.lock文件后,就开始执行这段代码


最后一句

$this->autoloadGenerator->dump()就是生成代码核心
也就是这个文件composer\src\Composer\Autoload\AutoloadGenerator.php

首先确定好两个目录变量

$vendorPathCode52 = str_replace('__DIR__', 'dirname(__FILE__)', $vendorPathCode);
$vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);

$appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true);
$appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);

然后依次从先前下载的所有依赖包获取自动加载设置

// Collect information from all packages.
$packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages());
$autoloads = $this->parseAutoloads($packageMap, $mainPackage); 
parseAutoloads()函数代码如下
public function parseAutoloads(array $packageMap, PackageInterface $mainPackage)
{
    $mainPackageMap = array_shift($packageMap);
    $sortedPackageMap = $this->sortPackageMap($packageMap);
    $sortedPackageMap[] = $mainPackageMap;
    array_unshift($packageMap, $mainPackageMap);

    $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
    $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
    $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $mainPackage);
    $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
    $exclude = $this->parseAutoloadsType($sortedPackageMap, 'exclude-from-classmap', $mainPackage);

    krsort($psr0);
    krsort($psr4);

    return array(
        'psr-0' => $psr0,
        'psr-4' => $psr4,
        'classmap' => $classmap,
        'files' => $files,
        'exclude-from-classmap' => $exclude,
    );
}

这些配置都在各个依赖包的composer.json中;

然后先生成namespaceFile

// Process the 'psr-0' base directories.
foreach ($autoloads['psr-0'] as $namespace => $paths) {
    $exportedPaths = array();
    foreach ($paths as $path) {
        $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
    }
    $exportedPrefix = var_export($namespace, true);
    $namespacesFile .= "    $exportedPrefix => ";
    $namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n";
}
$namespacesFile .= ");\n";

再生成psr4File

// Process the 'psr-4' base directories.
foreach ($autoloads['psr-4'] as $namespace => $paths) {
    $exportedPaths = array();
    foreach ($paths as $path) {
        $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
    }
    $exportedPrefix = var_export($namespace, true);
    $psr4File .= "    $exportedPrefix => ";
    $psr4File .= "array(".implode(', ', $exportedPaths)."),\n";
}
$psr4File .= ");\n";

再生成classmapFile

ksort($classMap);
foreach ($classMap as $class => $code) {
    $classmapFile .= '    '.var_export($class, true).' => '.$code;
}
$classmapFile .= ");\n";

最后导入到文件中

file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
file_put_contents($targetDir.'/autoload_psr4.php', $psr4File);
file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);

另外还生成这几个文件

file_put_contents($targetDir.'/autoload_static.php', $this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath, $staticPhpVersion));
file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFileContents, $targetDirLoader, (bool) $includeFilesFileContents, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader, $staticPhpVersion));
$this->safeCopy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
$this->safeCopy(__DIR__.'/../../../LICENSE', $targetDir.'/LICENSE');
完毕!



在Symfony 3项目中,`composer.json` 文件用于定义项目的依赖关系、自动加载规则以及其他配置选项。以下是一个典型的 Symfony 3 项目的 `composer.json` 文件结构示例: ```json { "name": "symfony/framework-standard-edition", "description": "The \"Symfony Standard Edition\" distribution", "autoload": { "psr-4": { "AppBundle\\": "src/AppBundle" }, "classmap": ["app/AppKernel.php", "app/AppCache.php"] }, "require": { "php": "^5.5.9|>=7.0.8", "symfony/symfony": "3.4.*", "doctrine/orm": "^2.5", "doctrine/doctrine-bundle": "~1.6", "symfony/swiftmailer-bundle": "~2.3,>=2.3.10", "symfony/monolog-bundle": "^3.0.2", "symfony/polyfill-apcu": "^1.0", "sensio/distribution-bundle": "~5.0", "sensio/framework-extra-bundle": "^3.0.2", "incenteev/composer-parameter-handler": "^2.0" }, "require-dev": { "sensio/generator-bundle": "~3.0" }, "scripts": { "post-install-cmd": [ "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" ], "post-update-cmd": [ "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" ] }, "extra": { "symfony-app-dir": "app", "symfony-bin-dir": "bin", "symfony-var-dir": "var", "symfony-web-dir": "web", "symfony-tests-dir": "tests", "symfony-assets-install": "relative", "incenteev-parameters": { "file": "app/config/parameters.yml" } } } ``` 该文件的结构主要包含以下几个部分: - **autoload**:定义了 PHP 的自动加载规则,例如使用 PSR-4 标准将 `AppBundle\\` 命名空间映射到 `src/AppBundle` 目录。 - **require**:列出了项目运行所需的依赖包及其版本要求,例如 Symfony 框架核心库 `symfony/symfony` 和数据库 ORM 支持 `doctrine/orm`。 - **require-dev**:列出开发时需要的额外工具,例如代码生成器 `sensio/generator-bundle`。 - **scripts**:定义了 Composer 脚本钩子,例如在安装或更新依赖后执行的命令,包括参数生成和缓存清理等操作[^4]。 - **extra**:包含特定于 Symfony 的配置信息,例如应用目录 (`symfony-app-dir`)、公共 Web 目录 (`symfony-web-dir`) 等。 通过这个 `composer.json` 文件,开发者可以轻松管理 Symfony 3 项目中的依赖库,并确保团队成员之间的环境一致性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值