关于 composer 易忽略的知识

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 installcomposer 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中,每个类都应该有自己的文件。这些类文件需要通过requireinclude语句来加载。但是,当应用程序的规模变得越来越大,类的数量也会增加,手动管理这些类文件会变得非常麻烦。这时可以使用Composer的自动加载功能,帮助我们快速地加载类文件。

3.1 什么是自动加载?

自动加载是指在PHP应用程序中,无需手动引入类文件,程序可以自动加载类文件。这样可以避免在代码中写大量的requireinclude语句。

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-dirautoload中的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会安装requirerequire-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将安装requirerequire-dev选项中指定的所有依赖包。

5.2 autoload和autoload-dev选项的区别

autoload选项用于指定生产环境中需要加载的类文件,autoload-dev选项用于指定开发环境中需要加载的类文件。在运行composer install命令时,Composer会自动加载autoloadautoload-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选项中指定的类文件。在测试程序中,我们需要加载autoloadautoload-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文件的大小和性能。