Composer 不是一个包管理器。是的,它涉及 “packages” 和 “libraries”,但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装。默认情况下它不会在全局安装任何东西。因此,这仅仅是一个依赖管理。
在项目中如果需要依赖其他包,可以使用composer来进行管理。需要在你的项目根目录下定义一个composer.json的文件,然后使用composer install
命令来进行依赖包的安装。如果之前已经安装过,而依赖包版本出现变化,现需要更新,可使用composer update
来进行依赖包的更新,composer会自动删除旧的文件。
composer安装
composer程序的安装可以参考官网步骤来进行。
编写composer.json
在你的文件中如果依赖其他包,需要创建composer.json文件来,并依照官网来进行编写。例如:
composer.json
{
"name": "json/Test", 开发商名\项目名
//repositories 包资源数组,列出依赖的资源,如果没有编写则在pakagist进行查找
"repositories": [
{
"type": "vcs", //资源包类型
"url": "https://github.com/jasonxieRD/test" //地址
}
],
"require": {
"Test/Test": "dev-master" // 开发商名\项目名 : 版本
}
}
编写好composer.json文件后,使用命令
composer install
会解析依赖的包,并下载到根目录中vendor文件夹下。这时同时生成一个composer.lock文件,该文件中描述依赖包的信息,它将帮助你的团队始终针对同一个依赖版本进行测试。任何时候,这个锁文件都只对于你的项目产生影响。
创建资源包
如果需要创建自己的资源包,同样需要composer.json文件,其中require字段不是必须的。如果想要使用autoload,资源包中composer.json需要在文件中编写autoload字段。例如:
{
"name": "Test/Test", //资源包名
"autoload": {
"psr-4": { //规范 有psr-0、psr-4、calssmap、files
"Test\\": "Test" //namespace : autoload 命名空间路径
}
}
}
这时,依赖该资源包的项目,在composer生成的vendor文件中会同时生成autoload.php文件,该文件可以自动加载你需要的命名空间,即,可以直接调用资源包中的类。具体原理在下面介绍。
例如
<?php
require 'vendor/autoload.php';
$ttt = new Test\Test();
$ttt->sayhello();
?>
autoload原理
- autoload.php文件中加载,composer/autoload_real.php文件,并调用方法
return ComposerAutoloaderInitd×××××××××××::getLoader(); (××一大串唬人的数字+字符)
这里引入了几个文件,这些文件是由composer自动生成的,当依赖关系发生改变时不需要修改这些脚本,运行composer重新生成即可。
..../vendor/composer/autoloade_namespace.php //其中为定义psr-0,命名空间与路径映射
..../vendor/composer/autoloade_prs4.php//其中为定义psr-4,命名空间与路径映射
..../vendor/composer/autoloade_classmap.php//其中为定义classmap,类与路径映射
..../vendor/composer/autoloade_files.php//其中为定义files,命名空间与路径映射
- 一系列设置。将psr0、psr4、classmap的映射关系分别设置到ClassLoader.php中类ClassLoader中对应的属性。
$loader->register(true);
注册ClassLoader类中loadClass方法注册到__autoload()中;- 然后在 new 类时,会自动调用loadclass方法,并根据类名调用
findFile($class)
,查找类的定义文件$file
,然后include $file
。
至此将需要的类加载进来。
代码清单
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
这里设置了欲注册的自动装载函数 $this->loadClass()
。
现在打开loadClass()
的定义
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
这里有个 findFile() 函数,如果相关类的声明所在文件的路径找到了,就包含并运行该文件,然后返回 true 。
接着打开findFile()的定义
public function findFile($class){
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('//' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
return $file;
}
- 先是判断类名是否以
'/'
开始,如果是的话,清除开头的'/'
; - 接着,检查当前类的名字是否在 类名与声明当前类的文件的路径的关系数组中,如果存在,直接返回相关键值(类文件路径信息)。如果上一步没有返回路径信息,执行
findFileWithExtension($class, '.php')
继续查找类文件路径信息; - 如果仍未找到类的文件路径信息,返回值为 null 且定义了 HHVM_VERSION 信息,则用
'.hh'
后缀继续查找类文件信息。HHVM_VERSION 是 HHVM版本信息? HHVM 是 Facebook 开发的高性能 PHP 虚拟机,宣称比官方的快9倍。 - 如果仍未找到,则返回 false 。