Composer 功能
composer 是依赖管理工具, 它用来解决如下几个问题:
有一个项目依赖于若干个库
其中一些库依赖于其他库
声明你所依赖的东西
找出哪个版本的包需要安装,并安装它们(将它们下载到你的项目中)
Composer 常用文件
composer.json
关键字 含义 详解 name 包名 monolog/monolog description 描述 version 版本 type 安装类型 - library- project- metapackage- composer-plugin license 许可协议 require 指定依赖包 包名: - 提供商名称- 项目名称- monolog/monolog包版本:- >, >=, |- *- ~ 下一个重要版本 require-dev 开发测试依赖包 --no-dev 参数可以跳过安装这些包 autoload -> psr-0 命名空间到实际路径映射 autoload -> psr-4 命名空间到实际路径映射 autoload -> classmap 引用所有组合 autoload -> files 载入文件 minimum-stability 设定的最低稳定性的版本 - dev- alpha- beta- RC- stable prefer-stable 优先使用更稳定的包版本 repositories 自定义的包资源库 - composer- vcs- pear- package按顺序遍历查找 config 配置 process-timeoutpreferred-installgithub-protocolsgithub-oauthvendor-dirbin-dircache-dircache-files-dircache-repo-dircache-vcs-dircache-files-ttlcache-files-maxsizeprepend-autoloaderautoloader-suffixoptimize-autoloadergithub-domainsnotify-on-installdiscard-changes composer.lock
composer install 命令将会检测锁文件是否存在,存在,将下载指定的版本(忽略composer.json 文件中的定义)
如果不存在 composer.lock 文件, composer 将读取 composer.json 并创建锁文件。
如果更新版本,使用 composer update, 这将获取最新匹配版本,并新建锁文件。
composer 常用命令
命令 | 含义 |
---|---|
composer list | 获取帮助信息 |
composer init | 以交互方式填写 composer.josn 文件信息 |
composer search | 根据关键字查找依赖包 (http://packagist.org 上查找) |
composer require | 引入、安装依赖包。等同于编辑 composer.json 文件,然后执行 install 命令 |
composer install | 安装 composer.json 中声明的依赖包 |
composer update | 更新依赖包。等同于删除 composer.lock 文件,然后执行 install |
composer remove | 移除指定的包依赖 |
composer clear | 清除 composer 缓存包 |
composer show | 查看安装的依赖包信息。 |
composer validate | 检测 composer.json 文件是否有效 |
composer self-update | 将 composer 工具更新到最新版本 |
composer create-project | 基于 composer 创建一个新的项目 |
composer dumpautoload | 生成 autoload 配置信息 |
Composer 自动加载原理
通过命名空间转换成对应目录的文件, 然后把 loadClass() 函数注册到 PHP 的 SPL 函数堆栈中, 每当 PHP 遇到不认识的的命名空间时, 就会调用函数堆栈中的每个函数, 直到加载命名空间成功。具体的实现分为了如下四个阶段:
启动阶段
加载启动文件和函数
初始化阶段
顶层命名空间和文件目录的映射
注册阶段
顶层以下命名空间和文件目录的映射
类文件的加载
注册函数到 spl_autoload_register 中
运行阶段
查找类并执行
因此, 只需在应用文件中,添加如下代码, 就可以实现代码的自动加载
require 'vendor/autoload.php';
Composer 自动加载实现
启动阶段
执行 autoload.php
# autoload.phprequire_once __DIR__ . '/composer/autoload_real.php';return ComposerAutoloaderInitc6ccc601ff2058fdea354619c8fd4fea::getLoader();
初始化阶段
执行 autoload_real.php
# autoload_real.php public static function getLoader() { # 构造单例 if (null !== self::$loader) { return self::$loader; } # 注册 「类加载」 类 spl_autoload_register(array('ComposerAutoloaderInitc6ccc601ff2058fdea354619c8fd4fea', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitc6ccc601ff2058fdea354619c8fd4fea', '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\ComposerStaticInitc6ccc601ff2058fdea354619c8fd4fea::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\ComposerStaticInitc6ccc601ff2058fdea354619c8fd4fea::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { composerRequirec6ccc601ff2058fdea354619c8fd4fea($fileIdentifier, $file); } return $loader; }
注册 「类加载」 类
spl_autoload_register(array('ComposerAutoloaderInitc6ccc601ff2058fdea354619c8fd4fea', 'loadClassLoader'), true, true);self::$loader = $loader = new \Composer\Autoload\ClassLoader();spl_autoload_unregister(array('ComposerAutoloaderInitc6ccc601ff2058fdea354619c8fd4fea', 'loadClassLoader'));
创建 ClassLoader 类, 该类是核心类, 完成了 命名空间和文件目录的映射, 类文件的加载, 类的生成等多种功能。
2 类文件配置信息的加载
$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);}
autoload_namespaces.php
return array( 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), 'Diff' => array($vendorDir . '/phpspec/php-diff/lib'), 'Behat\\Gherkin' => array($vendorDir . '/behat/gherkin/src'),);
文件中直接定义了, 顶级命名空间和文件目录的映射关系。
autoload_psr4.php
return array( 'yii\\swiftmailer\\' => array($vendorDir . '/yiisoft/yii2-swiftmailer/src'), 'yii\\gii\\' => array($vendorDir . '/yiisoft/yii2-gii/src'), 'yii\\faker\\' => array($vendorDir . '/yiisoft/yii2-faker'), 'yii\\debug\\' => array($vendorDir . '/yiisoft/yii2-debug/src'), 'yii\\composer\\' => array($vendorDir . '/yiisoft/yii2-composer'), 'yii\\bootstrap\\' => array($vendorDir . '/yiisoft/yii2-bootstrap/src'), 'yii\\' => array($vendorDir . '/yiisoft/yii2'),);
文件中直接定义了, 顶级命名空间和文件目录的映射关系
autoload_classmap.php
return array( 'Codeception\\Exception\\ExternalUrlException' => $vendorDir . '/codeception/lib-innerbrowser/src/Codeception/Exception/ExternalUrlException.php', 'Codeception\\Lib\\Connector\\Yii2' => $vendorDir . '/codeception/module-yii2/src/Codeception/Lib/Connector/Yii2.php', )
文件中直接定义了, 命名空间和文件的映射关系
注册阶段
# 注册 类$loader->register(true);public function register($prepend = false){ spl_autoload_register(array($this, 'loadClass'), true, $prepend);}
通过 spl_autoload_register 把所有函数注册的 PHP 环境中
public function loadClass($class){ if ($file = $this->findFile($class)) { includeFile($file); return true; }}
另外, autoload_files.php 中, 定义了所有的全局函数的文件
return array( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',)
运行阶段
如果代码中运行 new phpDocumentor\Reflection\Element(),PHP 会通过 SPL_autoload_register 调用 loadClass -> findFile -> findFileWithExtension 这样的机制, 去查找类所在的文件,并加载类到内存中。具体操作如下:
'__DIR__/../phpdocumentor/reflection-common/src + substr(phpDocumentor/Reflection/Element.php,25)'
如果失败,则利用 fallbackDirsPsr4 数组里面的目录继续判断是否存在文件
最后, 加载查找到的类到内存中。
将 \ 转为文件分隔符/,加上后缀php,变成 $logicalPathPsr4, 即 phpDocumentor/Reflection//Element.php;
利用命名空间第一个字母p作为前缀索引搜索 prefixLengthsPsr4 数组,查到下面这个数组:
'p' => array ( 'phpDocumentor\\Reflection\\' => 25, 'phpDocumentor\\Fake\\' => 19, )
遍历这个数组,得到两个顶层命名空间 phpDocumentor\Reflection\ 和 phpDocumentor\Fake\
在这个数组中查找 phpDocumentor\Reflection\Element,找出 phpDocumentor\Reflection\ 这个顶层命名空间并且长度为25。
在prefixDirsPsr4 映射数组中得到phpDocumentor\Reflection\ 的目录映射为:
'phpDocumentor\\Reflection\\' => array ( 0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src', 1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', 2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',),
遍历这个映射数组,得到三个目录映射;
查看 “目录+文件分隔符//+substr($logicalPathPsr4, $length)”文件是否存在,存在即返回。这里就是
Composer 管理自动加载
# composer.json{ "autoload": { "psr-4": {"Acme\\": "src/"} }}
composer.json 文件中添加 autoload 映射关系, 并通过命令 composer dumpautoload 可自动添加配置信息到文件 autoload_psr4.php 中
Composer 常用网站
官网
https://getcomposer.org/
https://www.phpcomposer.com/
依赖包库
https://packagist.org/
Composer 配置阿里云站点
$ composer clear // 一定要清空历史数据$ composer config --unset repos.packagist // 一定要取消官网库,否则更新速度很慢$ composer config repo.packagist composer https://mirrors.aliyun.com/composer/