1. 什么是Composer?
在开始讨论Composer的易忽略知识之前,我们先来回顾一下Composer是什么。Composer是一款PHP的包管理器,它帮助开发人员简化了包之间的依赖关系,并提高了开发效率。Composer使用JSON文件来管理包之间的依赖关系,可以轻松地下载和安装PHP包。
// 安装 Composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
2. 使用版本控制工具来管理composer.lock
2.1 什么是composer.lock
composer.lock是Composer生成的文件,记录了项目中每个依赖包的版本号,以及它们之间的依赖关系。这个文件的作用是确保在不同的环境中运行应用程序时,依赖包的版本号始终保持一致。
当运行composer install
或composer update
命令时,Composer会检查composer.lock文件,根据它所记录的版本号来安装或更新依赖包。
2.2 使用版本控制工具来管理composer.lock文件
由于composer.lock文件的作用非常重要,因此我们需要将它纳入到版本控制系统中。这样可以确保在不同的开发者之间,依赖包的版本保持一致。同时,在不同的环境中运行应用程序时,可以使用相同的依赖包版本,从而避免因为版本不同导致的问题。
建议将composer.lock文件提交到版本控制系统中,通常是git。以下是一个例子:
// composer.json 文件
{
"require": {
"vendor/package": "1.0.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
}
}
// composer.lock 文件
{
"hash": "81fbd...",
"packages": [
{
"name": "vendor/package",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/vendor/package.git",
"reference": "6f587..."
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vendor/package/zipball/6f587...",
"reference": "6f587...",
"shasum": ""
}
}
],
"packages-dev": [
{
"name": "phpunit/phpunit",
"version": "9.4.3",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {"PHPUnit\\": "src/"}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [...],
"description": "The PHP Unit Testing framework."
}
],
"packages-dev-included": [],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}
3. 使用Composer自动加载类文件
在PHP中,每个类都应该有自己的文件。这些类文件需要通过require
或include
语句来加载。但是,当应用程序的规模变得越来越大,类的数量也会增加,手动管理这些类文件会变得非常麻烦。这时可以使用Composer的自动加载功能,帮助我们快速地加载类文件。
3.1 什么是自动加载?
自动加载是指在PHP应用程序中,无需手动引入类文件,程序可以自动加载类文件。这样可以避免在代码中写大量的require
或include
语句。
Composer通过使用PSR-4标准来实现自动加载功能。其原理是根据类的命名空间来确定类的文件位置。
3.2 如何使用自动加载?
使用自动加载非常简单,只需在composer.json
文件中指定要自动加载的目录和命名空间即可。
// composer.json 文件
{
"autoload": {
"psr-4": {"Acme\\": "src/"}
}
}
// src/User.php 文件
namespace Acme;
class User
{
// ...
}
// index.php 文件
require 'vendor/autoload.php';
$user = new \Acme\User();
在上面的例子中,我们将Acme
命名空间下的类文件放在了src
目录中。然后,在composer.json
文件中指定了Acme
命名空间的根目录为src
目录。最后,在应用程序中使用new
关键字来创建User
类对象。
4. 使用Composer自定义命名空间
在使用Composer自动加载类文件时,有时需要自定义命名空间。例如,我们可能希望将一些第三方类库的命名空间与我们自己应用程序的命名空间分开。
Composer通过vendor-dir
和autoload
中的files
选项来实现自定义命名空间。
4.1 vendor-dir选项
vendor-dir
选项可以指定Composer的packages目录所在的位置。默认情况下,这个目录在项目的根目录下,其路径为vendor
。如果需要将这个目录移动到其他位置,可以使用vendor-dir
选项来实现。
// composer.json 文件
{
"config": {
"vendor-dir": "path/to/vendor"
}
}
上面的例子中,我们将vendor-dir
选项设置为path/to/vendor
,表示Composer的packages目录将会在这个位置。
4.2 类文件中的自定义命名空间
有时我们需要使用一些没有命名空间的类文件,但是这些类文件的命名与应用程序中的类产生了冲突。这时可以使用files
选项来加载这些类文件,并为它们指定自定义的命名空间。
// composer.json 文件
{
"autoload": {
"files": ["path/to/legacy/File.php"],
"psr-4": {"Acme\\": "src/"}
}
}
// path/to/legacy/File.php 文件
class File
{
// ...
}
// index.php 文件
require 'vendor/autoload.php';
$file = new \Acme\File();
在上面的例子中,我们使用files
选项来加载File
类文件,并为它指定了Acme
命名空间。最后,在应用程序中使用new
关键字来创建File
类对象。
5. 使用Composer管理开发依赖与生产依赖
在开发PHP应用程序时,通常会使用一些开发依赖,例如调试工具、代码分析工具等。这些开发依赖通常只在开发阶段使用,不需要在生产环境中运行。Composer提供了一些选项来管理开发依赖与生产依赖。
5.1 require和require-dev选项的区别
require
选项用于指定生产依赖,require-dev
选项用于指定开发依赖。在运行composer install
命令时,Composer会安装require
和require-dev
选项中指定的依赖包。
在应用程序部署到生产环境时,不需要安装require-dev
选项中指定的依赖包。这时可以使用--no-dev
选项,禁用require-dev
选项中的依赖包。
// composer.json 文件
{
"require": {
"vendor/package": "1.0.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
}
}
// 安装生产依赖
composer install --no-dev
// 安装所有依赖
composer install
上面的例子中,如果我们运行composer install --no-dev
命令,Composer将只安装require
选项中指定的依赖包,不会安装require-dev
选项中的依赖包。如果我们运行composer install
命令,Composer将安装require
和require-dev
选项中指定的所有依赖包。
5.2 autoload和autoload-dev选项的区别
autoload
选项用于指定生产环境中需要加载的类文件,autoload-dev
选项用于指定开发环境中需要加载的类文件。在运行composer install
命令时,Composer会自动加载autoload
和autoload-dev
选项中指定的类文件。
这两个选项的区别在于它们指定的类文件所在的目录。autoload
选项指定的类文件位于src
目录,而autoload-dev
选项指定的类文件位于tests
目录(或其他开发代码目录)。在运行composer install --no-dev
命令时,Composer不会加载autoload-dev
选项中指定的类文件。
// composer.json 文件
{
"autoload": {
"psr-4": {"Acme\\": "src/"}
},
"autoload-dev": {
"psr-4": {"Acme\\Test\\": "tests/"}
}
}
// 应用程序中的代码
require 'vendor/autoload.php';
$user = new \Acme\User();
// 测试程序中的代码
require 'vendor/autoload.php';
$testCase = new \Acme\Test\TestCase();
上面的例子中,Acme\User
类文件位于src
目录,Acme\Test\TestCase
类文件位于tests
目录。在应用程序中,我们只需要加载autoload
选项中指定的类文件,不需要加载autoload-dev
选项中指定的类文件。在测试程序中,我们需要加载autoload
和autoload-dev
选项中指定的类文件。
6. 使用Composer优化自动加载性能
由于自动加载是一个非常基础而重要的功能,因此它的性能也尤为重要。Composer提供了一些选项来优化自动加载性能。
6.1 classmap选项和files选项
classmap
选项和files
选项可以用来优化自动加载性能。
classmap
选项可以指定类所在的文件,这样Composer就不需要根据命名空间来查找类所在的文件,而直接使用classmap
指定的文件来加载类。
files
选项可以指定要加载的文件。这些文件通常是一些没有命名空间的类文件,使用files
选项可以避免Composer扫描目录来查找这些文件。
// composer.json 文件
{
"autoload": {
"classmap": [
"src/",
"lib/file.php"
],
"files": [
"vendor/autoload.php"
]
}
}
上面的例子中,我们使用classmap
选项将src
目录和lib/file.php
文件纳入到自动加载机制中。这样Composer将会直接使用这些文件来加载类,而不需要扫描目录。我们使用files
选项将vendor/autoload.php
文件加载到应用程序中。
6.2 使用classmap生成器
在自动加载的机制中,如果类文件数量非常大,或者包含的目录层级较深,Composer会消耗较多的时间来查找类文件。为了优化性能,我们可以生成一个classmap文件,将类文件和类名的映射存储到文件中,然后让Composer直接加载这个classmap文件。
我们可以使用dump-autoload
命令来生成classmap文件。
composer dump-autoload --optimize
在使用--optimize
选项时,Composer会尝试优化classmap文件的大小和性能。